ETL-DJI-FlightHub
DJI FlightHub 2 UAS location tracking for CloudTAK
Polls the DJI FlightHub 2 OpenAPI for the location of aircraft, docks and remote controllers and submits them to TAK as Cursor-on-Target.
Architecture🔗
The FlightHub 2 OpenAPI is a polled REST API. Device lists describe which devices exist and whether they are online but do not contain coordinates - the location of a device is only published in its Thing Model (state), which has to be requested per device. Each scheduled invocation therefore makes three kinds of request:
| Step | Request | Purpose |
|---|---|---|
| 1 | GET /openapi/{version}/project | List the Projects in the Organization |
| 2 | GET /openapi/{version}/project/device | List the gateway (Dock or Remote Controller) & aircraft pairs of each Project |
| 3 | GET /openapi/{version}/device/{device_sn}/state | Thing Model of each online device, containing its location |
The default schedule is rate(10 seconds) so that a moving aircraft produces a usable track. Every invocation makes 1 + <projects> + <online devices> requests, so an Organization with 3 Projects and 5 online devices makes 9 requests every 10 seconds. Setting DJI_PROJECTS does not remove the Project list request, as it is the source of the Project names, but does limit the device list requests.
Sub-minute schedules are run by the CloudTAK events pool rather than AWS EventBridge. Invocations are not queued behind one another, so the schedule should be lengthened if an invocation regularly takes longer than the schedule interval.
A failure to list the Projects fails the invocation. A failure for a single Project or device is logged and the remaining devices are still submitted.
Feature Mapping🔗
| Device | CoT Type | Callsign |
|---|---|---|
| Aircraft | a-f-A-M-H-Q | Device alias, otherwise <gateway alias> <model> |
| Dock | a-f-G-I-B-A | Device alias, otherwise <model> <serial> |
| Remote Controller | a-f-G-U-C-V-U-R | Device alias, otherwise <model> <serial> |
| CoT | Thing Model Property | Notes |
|---|---|---|
uid | sn | Prefixed: dji-<sn> |
| Point | longitude, latitude, height | height is relative to the ellipsoid, matching CoT HAE. Devices reporting 0,0 have no position fix and are skipped |
course | attitude_head | Aircraft only. Published as -180 to 180 from true north, normalized to 0 to 360 |
speed | horizontal_speed | Aircraft only. m/s |
sensor | <payload index>.gimbal_yaw, gimbal_pitch | Airborne aircraft only. FoV (45) & range (100m) are constants as neither is published |
Status, battery, height above takeoff, satellite counts and the owning Project are included in the remarks and in the feature metadata.
Configuration🔗
| Field | Description |
|---|---|
DJI_ORG_KEY | Organization Key, sent as the X-User-Token header. FlightHub 2: My Organization > Organization Settings > FlightHub Sync (labelled OpenAPI or Cloud Interconnect in some versions) > Organization Key |
DJI_API_URL | OpenAPI base URL - default https://es-flight-api-us.djigate.com. See Regions |
DJI_API_VERSION | v2.0 (default) or v0.1. See API Versions |
DJI_PROJECTS | Optional list of Project UUIDs to limit the ETL to. If empty every Project in the Organization is used |
INCLUDE_DOCKS | Submit Dock locations (default true) |
INCLUDE_CONTROLLERS | Submit Remote Controller locations, which is the location of the pilot (default true) |
INCLUDE_OFFLINE | Also request the state of devices reported as offline (default false) |
DEBUG | Print submitted features in the logs |
The Organization Key is a JWT tied to the user that generated it. That user must be a member of each Project that is to be tracked, otherwise the Project's devices cannot be listed.
Regions🔗
An Organization Key is only accepted by the region that issued it - a key presented to another region is rejected as unauthorized.
| Region | Base URL |
|---|---|
| United States | https://es-flight-api-us.djigate.com |
| Europe | https://es-flight-api-eu.djigate.com |
| China | https://es-flight-api-cn.djigate.com |
| On-Premises | The address of the deployment - ie http://<host>:30812 |
Private addresses are blocked by default. Set the DJI_UNSAFE_URLS environment variable on the task to allow the configured DJI_API_URL when developing against a local or on-premises deployment.
API Versions🔗
DJI publishes two generations of the OpenAPI. The three requests used by this ETL have the same path, headers and response structure in both, so the version only changes the path prefix.
DJI_API_VERSION | DJI Documentation | Notes |
|---|---|---|
v2.0 | OpenAPI V2.0 (Public Cloud) | Current version |
v0.1 | OpenAPI V1.0 | The V1.0 documentation uses the /openapi/v0.1 path prefix |
The On-Premises edition of OpenAPI V2.0 uses different paths for the Project list and is not supported. On-Premises deployments should use v0.1.
API Documentation🔗
The integration was built from the following documentation.
DJI FlightHub 2 OpenAPI V2.0 (Public Cloud)🔗
- API Introduction - FlightHub 2 User Manual
- Interface Documentation
- Authentication Tutorial -
X-User-Token&X-Project-Uuid, where to obtain the Organization Key - Device Management Tutorial - Project list => device list => Thing Model flow
- Get Project List Under Organization -
GET /openapi/v2.0/project - Get Project Device List -
GET /openapi/v2.0/project/device, integermode_codevalues - Get Thing Model -
GET /openapi/v2.0/device/{device_sn}/state, per model property definitions - Error Code
- Sample Source Code - DJI's device list demo.
KeyCenter.tsdocuments the form of the Public Cloud host andPublicCloud/DeviceListdocuments that the Public Cloud Thing Model uses named enums (mode_code: 'idle')
DJI FlightHub 2 OpenAPI V1.0🔗
- API Introduction - FlightHub 2 User Manual
- Interface Documentation
- Authentication Tutorial
- Device Management Tutorial
- Get the list of projects under the organization -
GET /openapi/v0.1/project - Obtain the list of devices under the project -
GET /openapi/v0.1/project/device - Device Model Retrieval -
GET /openapi/v0.1/device/{device_sn}/state
DJI Cloud API🔗
The Thing Model returned by FlightHub 2 is the device property set defined by the DJI Cloud API, which the OpenAPI documentation defers to for detail.
- Product Support - Device enums (
domain-type-sub_type) used to tell aircraft, docks & remote controllers apart - Device Properties - Property definitions, including the payload objects keyed by
{type-subtype-gimbalindex}
Third Party🔗
- dji-flighthub2-cli - Unofficial client validated against a live Organization. Source of the US & EU base URLs, and of observed behaviour that DJI does not document: errors are returned as an HTTP 200 with a non-zero
code, and empty lists are returned asnull
Verification🔗
DJI's documentation does not state the Public Cloud base URLs or any rate limit. What has and has not been confirmed:
- Confirmed: The US, EU & China hosts above answer unauthenticated requests for all three paths, on both
v0.1&v2.0, with{"code":200401,"message":"X-User-Token not found or empty"}. Unknown paths return a 404 - Not confirmed: The ETL has not been run against an Organization with devices. Response handling follows the documentation above and is covered by tests against a mock of the documented responses
- Assumed:
gimbal_yawis relative to true north, asattitude_headis documented to be. If sensor cones are drawn relative to the nose of the aircraft this assumption is wrong - Unknown: Rate limits. Error
210429(Operations too frequent) exists - lengthen the Layer schedule if it is logged
Development🔗
DFPC provided Lambda ETLs are currently all written in NodeJS through the use of a AWS Lambda optimized Docker container. Documentation for the Dockerfile can be found in the AWS Help Center
Add a .env file in the root directory that gives the ETL script the necessary variables to communicate with a local ETL server. When the ETL is deployed the ETL_API and ETL_LAYER variables will be provided by the Lambda Environment
To run the task, ensure the local CloudTAK server is running and then run with typescript runtime or build to JS and run natively with node
Tests run against a mock FlightHub 2 API and do not require credentials
Deployment🔗
Deployment into the CloudTAK environment for configuration is done via automatic releases to the DFPC AWS environment.
Github actions will build and push docker releases on every version tag which can then be automatically configured via the CloudTAK API.
Builds are performed by the cloudtak-etl script provided by @tak-ps/etl. It requires a capabilities.json document alongside the Dockerfile which describes the task (name, description, compute requirements, permissions & invocation types) and is validated and embedded in the OCI Image Manifest as a com.cloudtak.capabilities annotation so CloudTAK can read it directly from ECR before the task is ever deployed. Update capabilities.json whenever the task's requirements change.
To build & push manually:
export AWS_REGION='us-east-1'
export AWS_ACCOUNT_ID='123456789012'
export Environment='prod' # Optional - defaults to prod
npx cloudtak-etl
Non-DFPC users will need to setup their own docker => ECS build system via something like Github Actions or AWS Codebuild.
Info
This page is generated daily from the README of dfpc-coe/etl-dji-flight-hub (last fetched 2026-10-08). Changes should be made in that repository.