Who this guide is for
This interface is for developers and hobbyists whose device can send input data through an adapter on the local network. It does not decode an arbitrary Wi-Fi controller automatically. For compatible ExpressLRS firmware, use the separate ExpressLRS connection instead.
The interface is included in the Universal Controller update. Test while the simulated aircraft is grounded and disarmed, then use the game's mapping and activation steps.
Opt in on the phone
Put the phone and adapter on a suitable local IPv4 network. In Controllers, enter the adapter's source IPv4 address and choose Listen for Custom Wi-Fi. The adapter sends to the phone's IPv4 address, UDP port 11001. These are two different addresses.
No cloud service is used. Source-address checks reduce accidental cross-device input, but they do not authenticate a hostile local network. Use a trusted network. Choose Stop when finished; backgrounding the app also closes the listener.
Send a complete current sample
Send one UTF-8 JSON object per UDP datagram, no more than 4096 bytes:
{
"protocol": "dh-controller-v1",
"id": "my-radio-01",
"name": "My custom radio",
"seq": 1,
"axes": [0.0, -1.0, 0.0, 0.0],
"buttons": [false, false, false]
}
The sample values above are adapter data, not a universal throttle layout. The player maps the received axes and chooses the correct safe position for the current flight mode.
| Field | Requirement |
|---|---|
protocol |
Exactly dh-controller-v1 |
id |
Stable device identifier, 1–64 characters |
name |
Human-readable device name, 1–64 characters |
seq |
Increasing integer from 0 to 2^53−1 |
axes |
Finite numeric values from −1 to +1, up to Godot's JOY_AXIS_MAX slots |
buttons |
Boolean values, up to Godot's JOY_BUTTON_MAX slots |
At least one input array must contain entries. Omitted trailing axis slots become zero and omitted buttons are released; send the current state rather than a delta. Too many input slots, invalid values or invalid schema reject the packet. Keyboard-style custom inputs can be translated by your adapter into buttons/digital directions.
Keep the stream fresh
Send at least ten fresh packets per second; 50–100 Hz is a suitable starting range. Increment seq for every sample. Duplicates, out-of-range values, identity changes and packets from the wrong source address do not refresh the heartbeat.
After 500 ms without a valid fresh packet, input disconnects. If it owned flight, the game disarms and pauses. After loss, the same stable identity may start a new sequence, but it must be explicitly activated again. The source address plus stable ID identifies its saved profile.
Map, calibrate and test
Once valid packets arrive, select the detected custom device. Use the setup wizard to map channels/actions and the calibration guide to measure analog travel. Save a named profile and activate only with safe inputs.
Test disconnect by stopping the sender while grounded. Confirm the game pauses and disarms, restart the sender, then follow safe resume. Also test malformed packets, duplicate sequences and a second sender; none should silently preserve ownership or move the aircraft.
The automated transport checks used real local UDP sockets and synthetic samples. No physical custom adapter was attached during acceptance, so verify your actual network/device before relying on it for simulator sessions.

