DO NOT MERGE — Integration with external mission provider ollebo.com (read-only JSON telemetry export) - #21
Conversation
Adds a `json` encoder and an `http` output sink to the Telemetry Relay, so external services can consume live telemetry without implementing a binary FC protocol. No producer code is touched — the relay already taps the app's own `telemetry-*` events, so this works for MAVLink, MSP and passive links alike. - encoders/json.rs: explicit versioned camelCase DTO (not the internal cache structs, so the public contract isn't coupled to internals), stamped with a mission id and a monotonic seq. Self-rate-limits by returning an empty frame set, which Relay::emit_set already treats as "nothing to send" — otherwise a 50 Hz MAVLink attitude stream would emit 50 JSON frames/s. - output/http.rs: loopback-by-default HTTP server. GET /api/v1/telemetry (snapshot), /api/v1/stream (SSE), /api/v1/health. Hand-rolled on std::net::TcpListener, as tokio is built without net/rt-multi-thread; same approach as video/mjpeg_server.rs. Per-client write timeout, per-connection thread, and no lock held across a socket write, so one stalled consumer can't stall the relay dispatch thread. - The mission id is a hard gate: Relay::build resolves it before constructing the sink, so with none configured no port is ever bound. - HTTP output requires the JSON protocol (SSE-wrapping binary frames would be garbage). The reverse is allowed: JSON out serial/tcp/udp is valid NDJSON. DO NOT MERGE — proposal only; see the PR description. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Interesting extension and I will definitely reject it right away. I will have a closer look on it. Its planned to have external APIs for other applications to connect to anyway so something like this could be a good starting point. As you correctly stated, it will not be merged before final 1.0 But I will definitely consider it when the API implementation comes. One note beforehand: this json data stream could be added as a relay output instead so the user has control over when its active and when not. At the moment the relay feature is gated by a live connection, so it won't output anything for a log replay but that can be changed if necessary. |
|
I keep my fork up to date and see if I can get a full working test. I already have a mavProxy that I use with other GC tools, but it's nice to use the API directly at ollebo.com. |
|
If you go into your own fork under actions, there SHOULD be the release build action (afaik it gets copied with the fork). |
Build statusRan your branch through the full check set on Windows (touched both new files to
The "never compiled" caveat can come off. Windows only; nothing here is What I want changedWildcard CORS. The mission ID isn't a gate. Any non-empty string passes. "Genuinely off, not Lifecycle. The server appears on connect and vanishes on disconnect. A The blocking concern is mine, not yours
What remains on your side: a stalled SSE client still holds that thread for up to Smaller
Timing1.0 is in freeze, so this can't land now. I moved the target to |
|
Oh and one small detail: "JSON" in the output channel picker is not really fitting as a name there since its not clear what it actually does. and since its a universal API maybe we should call it like that. Something like "Kite API" or "Telemetry API"? |
DO NOT MERGE — proposal / conversation starter
I know Kite is in feature-freeze for 1.0 and that only bugfix PRs are being merged. This is not a merge request. It's a worked example, in code, of what an integration with an external mission provider could look like — so there's something concrete to react to instead of an issue full of hand-waving. Happy for it to sit, be closed, or be picked up after 1.0. If there's no interest, just say so and I'll close it myself.
Disclosure up front: I build Ollebo, the service used as the example consumer here. I've tried to keep that bias out of the code — see "Why there's no Ollebo code in Kite" below.
What this adds
A read-only JSON telemetry export: one new
Encoder(json) and one newOutputSink(http) inside the existing Telemetry Relay.That's the whole idea. The relay already taps the app's own
telemetry-*events backend-side, already has persisted config, a settings UI, connect/disconnect lifecycle, throughput stats and a reconfigure reconciler. So an external consumer can be added without touching a single producer — no changes tomavlink_proto,scheduler, orpassive_telemetry— and it works for MAVLink, MSP and passive links alike, because it rides the shared normalized cache.GET /api/v1/telemetry200 application/json— most recent frame (503before any telemetry arrives)GET /api/v1/stream200 text/event-stream— SSE, onedata:record per frameGET /api/v1/health200 application/json—{ ok, schema, missionId, hasData, streamClients }Today the only telemetry egress is a binary FC protocol (LTM / MAVLink / CRSF / SmartPort). Anything that just wants "where is the aircraft, is it armed" has to implement a protocol parser first. This closes that gap.
Design notes (the non-obvious bits)
tokiois built withoutnet/rt-multi-thread, so axum/hyper/tungstenite aren't on the table without a real dependency change. SSE hand-rolls in ~40 lines onstd::net::TcpListener— the same approachvideo/mjpeg_server.rsalready takes. No new crates.0.0.0.0because reaching the LAN is its whole purpose. A telemetry API is different — it shouldn't be silently readable by everyone on a field network. LAN exposure is an explicit per-relay opt-in.JsonEncoderreturns an emptyVecwhen called too soon andRelay::emit_setalready early-returns on that, so no frame is written and the counters stay honest. Default 5 Hz.HttpSink::writeruns on the Tauri event-listener thread that drives every relay's dispatch. So: per-client write timeout, dead clients dropped, no lock held across a socket write, and one thread per connection so a client that connects and goes silent can't block the accept loop.Serializeof the internal cache structs — those are snake_case internals that move with the frontend, and a public contract shouldn't be welded to them.armedis derived fromarmingFlagsbit 2 so consumers don't decode a bitfield.Relay::buildresolves it before constructing the sink, so with no mission id the relay is refused and no port is ever bound — off means off, not "serving untagged data". The UI flags the empty field, but the backend check is the authoritative one.What Ollebo is, and how it fits
Ollebo is a platform for drone maps and live missions — "the all-in-one platform to host high-resolution maps, analyze assets, and stream real-time telemetry". Two halves:
The base features are free — makers and drone hobbyists get the free tier, and the professionals paying for hosting fund it. It's built on open standards (MAVLink, MQTT), EU-hosted, and it is under heavy active development right now, so the integration surface is still moving and I'd rather shape it around what a real GCS actually wants to emit than guess.
Ingest is a plain HTTP
PUT /event/<mission-key>; Ollebo replays it on the mission's live map over its own SSE stream. It already accepts MAVLink via MAVProxy on UDP 14550 — so in principle Kite's existingmavlink+udprelay can already feed it, with MAVProxy in the middle. The point of this PR is that a JSON export removes that middle entirely, for Ollebo and for anything else.Why there's no Ollebo code in Kite
Deliberately: nothing in this diff mentions Ollebo. What's added is a vendor-neutral JSON export. Feeding Ollebo is then a ~40-line stdlib Python bridge that reads Kite's SSE stream and PUTs each frame — it lives in the design doc (
docs/dev/active/JSON_TELEMETRY_API.md), not in the app.That's the shape I'd argue for regardless of who's asking: Kite stays a GCS that serves telemetry, and consumers do their own pushing. Putting a third-party endpoint and a credential inside the app would be a much bigger ask, and a worse trade for the project.
Set a relay to JSON/HTTP with a mission id, connect, run the bridge, and the flight appears live on the Ollebo mission map.
If there's interest
I can start testing this properly — flying it against real hardware, on the Ollebo side and the Kite side, and reporting back. Ollebo's free tier means anyone here can try it without paying for anything. And if the JSON schema is wrong for what Kite wants to expose, I'd much rather change Ollebo than bend Kite around it.
Honest status
cargo checkhas not run againstencoders/json.rsoroutput/http.rs. Treat the backend as reviewed-by-eye, not verified. I'll fix whatever a build turns up if this is worth pursuing.npm run -s checkclean (549 files, 0 errors, 0 warnings).en/de/fr.Given all that, please read this as a design proposal with code attached, not as finished work.
🤖 Generated with Claude Code