Writing · drones
Live video and telemetry from DJI enterprise drones into a web map
By Mattias Hemmingsson · · 5 min read
In late October we opened up a new integration in Ollebo: DJI enterprise drones can stream their flights straight into the map. The drone shows up live while it flies, every flight is saved as a mission, photos upload by themselves, and live video goes to the whole team.
We did it without writing a mobile app. This post explains how.
No app: DJI Cloud API
DJI's enterprise controllers (RC Plus, RC Pro Enterprise) run an app called DJI Pilot 2. It has a feature called Cloud Services → Open Platform: you give it a URL, it opens that page in a webview, and the page can tell the controller to connect to your cloud over DJI's Cloud API. DJI Docks speak the same protocol.
So the "app" is one web page, and the rest is server-side:
Pilot 2 / Dock ──MQTT (TLS)──► EMQX broker ──auth hooks──► dji-api (web page, login, binding)
│ │
│ └──► dji-ingest ──► Postgres (devices, flights, tracks)
│ └──► NATS ──► API (server-sent events) ──► live map
├──S3 upload (short-lived credentials) ──► object storage ──► assets in the Space
└──RTMP ──► ollebo-video (MediaMTX) ──► HLS / WebRTC to viewers, archived for replay
This works with the Matrice 4, Matrice 30/300/350 and Mavic 3 Enterprise. Consumer drones (Mini, Air) don't have Cloud API; they need DJI's Mobile SDK and a real app.
What happens when a pilot connects
- In Pilot 2 the pilot opens Cloud Services → Open Platform and enters our URL.
- The page logs in with Keycloak (PKCE, as a normal web app) and lists the Spaces (teams) the pilot belongs to.
- It verifies our DJI app license with the controller. Nothing else works before that.
- It reads the controller's serial number and binds the controller to the chosen Space. The server stores the binding and issues an MQTT credential for that controller only.
- The controller connects to the MQTT broker and announces its aircraft. From now on the web page can be closed; Pilot 2 keeps the connection.
That's the only setup. After that, the pilot just flies.
Flights become missions
A separate worker, dji-ingest, listens to the telemetry:
- Takeoff opens a flight, a new mission in the Space named after the drone and date.
- Position and state go into the mission's track, and live to the map over NATS and server-sent events.
- Landing (with 2 minutes of grace), the aircraft or controller going offline, or 5 minutes of silence closes the flight.
The pilot doesn't create anything by hand. Fly, and the mission is there.
Photos and videos upload by themselves
With auto-upload on, Pilot 2 uploads every photo and video straight to object storage, and they show up as assets in the Space within a minute.
Pilot 2 can't use presigned URLs; it wants real S3 credentials. So the server hands out short-lived credentials that can only write under that controller's own folder. No read, no list, no delete, no other paths. When the upload callback comes in, the server moves the file into the Space's assets. A leaked credential can, at worst, drop files into one staging folder for a short while.
Live video
When the pilot (or someone on the web) presses Go live:
- the server registers a stream with ollebo-video for that flight's mission;
- the drone is told to push RTMP to the returned address;
- MediaMTX receives it and serves it as HLS (works everywhere) and WebRTC (low latency) to anyone in the Space;
- every segment is archived to object storage, so the flight's video can be replayed next to its track.
ollebo-video is a small control API in front of MediaMTX. A stream id is a random UUID and is the endpoint; publishing needs a separate stream key. You can test the whole path without a drone:
ffmpeg -re -i flight.mp4 -c:v libx264 -preset ultrafast -tune zerolatency \
-f rtsp -rtsp_transport tcp "rtsp://publish:<stream_key>@localhost:8554/<stream_id>"
ffplay "http://localhost:8888/<stream_id>/index.m3u8"
Keeping teams apart
Several companies use the same broker and the same bucket, so isolation is checked at every layer, not just one:
| Layer | Rule |
|---|---|
| MQTT broker | A controller can only publish and subscribe to its own exact topics. Every wildcard is denied. Only the ingest worker reads telemetry. |
| Topology | An aircraft belongs to one controller. Another team can't claim it. |
| Ingest | The Space is looked up in the database for every message, never taken from the message itself. Unknown data is dropped. |
| API | Space membership (Keycloak groups) is checked on every call, and the controller's token against its live binding. |
| Storage | Upload credentials are limited to one controller's folder. Callbacks for any other path are refused. |
| Audit | Binds, logins, credential changes, uploads, flights and live streams are all logged. |
Unbinding a controller revokes its MQTT credential and API token, and disconnects it right away.
Testing without hardware
You can't wait for a drone for every change, so the local setup fakes the hardware:
docker compose upstarts EMQX, Postgres/PostGIS, NATS, MinIO and a fake Keycloak.- A simulated RC Plus script connects, binds, "flies" and uploads, exactly like a real controller.
- The web page runs in a desktop browser with
?mock=1, which installs a fake DJI bridge. - One smoke test runs the whole path: bind, fly, check isolation, upload, unbind.
The fake identity provider signs real tokens, and the service verifies them exactly like real ones. There is no "auth off in dev" switch to forget in production.
Still testing on real hardware
Some things only real controllers can answer:
- MQTT over TLS from Pilot 2. DJI documents plain TCP and WebSocket. We give the controller a TLS address and are verifying it works; the fallback is secure WebSocket through the ingress. We won't offer unencrypted MQTT.
- Login inside the Pilot 2 webview. The PKCE redirect is expected to work; if not, a device-code login is the fallback.
- Encrypted video ingest. DJI documents
rtmp://. MediaMTX also accepts RTMPS and WHIP, and newer controllers may support them.
Want to try it?
If you fly a DJI enterprise drone for inspection, survey, public safety or anything else, we'd love to connect you. You'll see your drone live on your own map, and we get to hear what you'd want next. Automatic photo processing into maps and DJI Dock support are on the way. Get in touch through ollebo.com.
Filed underdrones · dji · video · mqtt · ollebo