Ollebo MAVProxy: receives MAVLink telemetry (UDP/14550) from a drone or ground station and
forwards selected messages to the Ollebo API (PUT ${OLLEBO_URL}/event/${missionKey}). Ships
with a small Flask config UI on port 8080 for editing the mission config and for handing the
operator the live-video stream URL.
Built/pushed by GitHub Actions to GHCR as ghcr.io/ollebo/mavproxy:latest (and :sha-<sha>).
Ports:
14550/udp+14550/tcp— MAVLink telemetry in8080/tcp— config web UI (OLLEBO_UI_PORT)
Key env vars: OLLEBO_URL, OLLEBO_MISSION_KEY, OLLEBO_MISSION_NAME,
OLLEBO_MISSION_DEVICE_NAME, OLLEBO_SAMPLE_INTERVAL, OLLEBO_UI_PORT, OLLEBO_CONFIG_PATH.
Deploys to the local cluster via Helm and exposes MAVLink over a UDP NodePort. mavproxy forwards
telemetry to the production API (https://api.ollebo.com by default — override via
config.url). The Helm chart lives in chart/.
# 1. The image is built & pushed to GHCR by CI on every push to main.
# (manual fallback: docker build -t ghcr.io/ollebo/mavproxy:latest . && docker push ...)
# 2. Namespace + mission key secret
kubectl create namespace mavproxy
kubectl -n mavproxy create secret generic mavproxy-ollebo \
--from-literal=OLLEBO_MISSION_KEY=<your-mission-key>
# 3. Install
helm install mavproxy ./chart -n mavproxy \
--set secret.existingSecret=mavproxy-ollebo
# (quick test alternative: skip step 2 and pass the key inline)
# helm install mavproxy ./chart -n mavproxy --set secret.missionKey=<key>NodePorts are reachable on any node IP (e.g. 10.0.0.30–10.0.0.33):
| Purpose | Address | Default nodePort |
|---|---|---|
| MAVLink UDP | <nodeIP>:30550 (udp) |
30550 |
| MAVLink TCP | <nodeIP>:30550 (tcp) |
30550 |
| Config UI | http://<nodeIP>:30808/ |
30808 |
Point your drone / GCS MAVLink output at <nodeIP>:30550 (UDP).
kubectl get pods,svc -n mavproxy
kubectl logs -n mavproxy deploy/mavproxy -fThe config UI has a Video stream section. Pressing Get stream URL (the first successful
Save does it too) runs the mission handshake — GET ${OLLEBO_URL}/mission/${missionKey}/hello
— which registers a stream with ollebo-video and returns an RTSP publish endpoint. The UI shows
it with the credentials already embedded:
rtsps://publish:<stream-key>@ingest.ollebo.com:443/<stream-id>
Point the drone's camera / encoder at that URL and the video is live; the HLS and WebRTC playback
links next to it are what viewers watch. The endpoint is stored in the config file (video), so
it survives restarts and page reloads — the button only mints a new one when you ask, and doing so
retires the previous URL. If the API replies without a video block, live video is not enabled on
that deployment and the rest of the proxy is unaffected.
Full reference (data flow, event schema, every field, more examples): docs/DATA.md.
Data reaches the mission two ways: MAVLink → the proxy (<nodeIP>:30550/udp, sub-sampled and
forwarded), or HTTP PUT → the API directly (what the proxy does under the hood — push anything
with curl). Events land in mission_data, keyed by the mission key.
tools/mav_test.py streams every supported MAVLink type (HEARTBEAT,
GPS_RAW_INT, GLOBAL_POSITION_INT, MISSION_CURRENT, SYS_STATUS) at the proxy and (--verify)
confirms each reached the API. No local deps via the pod wrapper:
tools/run-in-cluster.sh --verify --key <mission-key> # full test (exit 0 = all types received)
tools/run-in-cluster.sh # demo only — watch logs / config UI
tools/run-in-cluster.sh --types GPS_RAW_INT --sysid 7 # subset / a "new" vehicleStandalone (needs pip install pymavlink):
python3 tools/mav_test.py --host <nodeIP> --port 30550 --verify --key <mission-key>
python3 tools/mav_test.py --host 127.0.0.1 --port 14550 # vs a local docker runContinuous background stream (data keeps flowing while you inspect):
kubectl run mav-stream -n mavproxy --restart=Never --image=ghcr.io/ollebo/mavproxy:latest \
--command -- python3 -c "$(cat tools/mav_test.py)" --per-type 6000 --rate 5
kubectl delete pod mav-stream -n mavproxy # stopPush any event straight to the API — Content-Type: application/json is required. See
docs/DATA.md for the full field schema.
KEY=<mission-key>; API=https://api.ollebo.com
# a GPS point (geopoint is [lon, lat] in decimal degrees):
curl -X PUT -H 'Content-Type: application/json' \
-d '{"type":"GPS_RAW_INT","geopoint":[18.0686,59.3293],"device":"manual"}' "$API/event/$KEY"
# a custom reading — type is free-form, jsonData is arbitrary:
curl -X PUT -H 'Content-Type: application/json' \
-d '{"type":"SENSOR","temp":21.5,"humidity":48,"jsonData":{"co2_ppm":420}}' "$API/event/$KEY"
curl "$API/event/$KEY/recent?minutes=5" # read it back
curl "$API/mission/validate/$KEY" # check the key is validNotes: source sysid must not be 255 (the proxy filters GCS); each MAVLink type is sampled 1-in-10,
so the script sends a dozen of each; MISSION_CONNECTED/UNIT_REGISTERED fire once per proxy boot.
A GitOps Application is provided in argocd/application.yaml. It is
not needed for the Helm flow above; apply it only to manage mavproxy via ArgoCD (requires
ArgoCD SSH access to this repo):
kubectl apply -f argocd/application.yaml