Skip to content

About

Autel Cloud API SDK 是将 Autel 上云协议的常量与数据结构以纯 Java 类型(record + enum)表达的类型安全 POJO 库,作为第三方平台对接 Autel 机场与遥控器的协议定义层 + 航线工具套件单一真相源,消除协议定义的重复维护。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Autel Cloud API SDK

简介

Autel Cloud API SDK 是 Autel 上云协议的 Java 类型安全 POJO 库,覆盖机场上云(Dock ↔ 平台,MQTT 5 通道 services/drc/events/requests/status)与遥控器上云(Controller ↔ 平台,HTTP + WebSocket)场景,包含协议定义层(topic/method/envelope/error/command/model/telemetry)与航线工具套件(wayline Builder/Template/Codec),共 83 个 method、15 个 property、13 款设备型号。

为什么用这个 SDK?

  • 编译期类型安全——Autel JSON 字段名映射为 Java record 字段,拼写错误编译即报,不再运行时静默失败
  • 协议知识在 JAR 不在人脑——83 个 method 全部编码为类型安全的 record,IDE 自动补全即可发现全部能力,无需逐字阅读 Autel 文档
  • 专人跟踪协议变更——Autel 更新协议时由 SDK 维护者同步更新,消费方升级 JAR 即获取最新定义,无需自己盯文档
  • 100% 接口覆盖不随人员流动退化——核心成员离职不会导致代码无人敢改、平台兼容性永久降级;协议知识固化在代码中,团队能力不依赖个人记忆
  • 协议权威解释,持续验证完善——字段必填/选填、类型、回复结构等歧义由 SDK 一锤定音,消除团队内解读争议;当前已通过 Autel 官方文档核实的协议元素标注 @Verified,推断项标注 @Inferred 待真机验证,详见下方「验证状态说明」

作为模拟器与平台的共享"单一真相源",本 SDK 消除两个系统间协议定义的重复维护,升级一处即双方同步。

版本说明

本 SDK 跟随 Autel Cloud API 官方协议版本,当前最新协议版本为 1.3.0。

版本号格式:1.3.0.X

  • 前三段(1.3.0)对齐 Autel Cloud API 协议版本,协议升级时同步递增
  • 末段(X)为 SDK 问题修复版本号,协议不变情况下随 SDK 缺陷修复递增

特性

  • 全通道覆盖:services(40) / drc(1) / events(22) / requests(4) / status(1) = 68 个 method 枚举 + property/set(15) + 航线工具套件
  • 类型安全:每个 method 有对应的 Request/Reply/Data record,字段 camelCase 自动映射 Autel snake_case JSON
  • 文档追踪:@DocUrl 标注 Autel 文档链接,@Verified/@Inferred 标注验证状态
  • 零 MQTT 耦合:纯 POJO 定义层,不依赖 MQTT 客户端
  • Jackson SNAKE_CASE:MessageCodec 统一配置,snake_case ↔ camelCase 双向映射
  • 航线工具一体化:WPML 模板生成/解析工具与协议 POJO 共处一模块,Builder 模式构建航点/建图航线

快速开始

Maven 依赖

本 SDK 为单模块结构,协议定义层与航线工具套件在同一 JAR 中,一次引入即获得全部能力:

<dependency>
    <groupId>ltd.cdmi.autel</groupId>
    <artifactId>autel-cloud-api-sdk</artifactId>
    <version>1.3.0.0</version>
</dependency>

直接下载 JAR

非 Maven 项目可直接下载预构建 JAR(包含源码包):

平台 下载地址
GitHub releases/latest
Gitee releases

JAR 文件名格式:autel-cloud-api-sdk-{version}.jar

通用调用模式

SDK 提供三个对称入口,分别对应三类协议通道,调用方式完全一致(先提取消息类型 → switch 路由 → parse 反序列化为类型安全 POJO):

协议通道 提取消息类型 反序列化入口 适用场景
MQTT MessageCodec.extractMethod(payload) MessageCodec.parse(payload, Class) 机场上云(services/drc/events/requests/status 5 通道)
WebSocket WsPushMessage.extractBizCode(payload) WsPushMessage.parse(payload, Class) 平台推送(平台 → 前端)
HTTP — HttpResponseEnvelope.parse(body, Class) HTTP API 请求(前端 → 平台)

每条通道的 parse 工厂方法归位到产出类型所在的包:MQTT 信封 AutelMessage 位于 codec 包,WS 信封 WsPushMessage 位于 websocket 包,HTTP 信封 HttpResponseEnvelope 位于 http 包。避免 codec 基础设施层反向依赖上层业务类型。

机场上云(MQTT)示例:5 个 MQTT 通道信封结构一致 {method, tid, bid?, data},用 switch + parse 模式,每个 case 1 行 parse,其余是类型安全业务代码:

String method = MessageCodec.extractMethod(payload);
switch (method) {
    case "fly_to_point" -> {
        var msg = MessageCodec.parse(payload, FlyToPointRequest.class);
        msg.data().flyToId();          // 编译期类型安全,无需 cast
        String reply = MessageCodec.toJson(new NoOutputReply());
        sendReply(msg.tid(), reply);   // 发到 thing/product/{sn}/services_reply
    }
    default -> log.warn("未处理: {}", method);
}

事件通道同样使用 parse,回复用 events_reply:

var msg = MessageCodec.parse(payload, FlighttaskProgressData.class);
msg.data().output().status();          // 编译期类型安全
sendEventReply(msg.tid(), 0);           // tid 与原始 event 一致

场景一:机场上云(Dock ↔ 平台,MQTT 5 通道)

机场上云场景中,Dock 机场通过 MQTT 与云平台交互,覆盖 services/drc/events/requests/status 全部 5 个通道。SDK 不绑定 MQTT 客户端实现,调用方自行接入任意 MQTT 客户端,按 extractMethod + parse 模式处理消息。以下按 Autel Cloud API 业务功能划分,列出每个功能涉及的 SDK 类与调用方式,全部基于 MQTT 协议。

1. 设备注册与上线

通道:requests(绑定流程)+ status(上线拓扑)

// 绑定流程:airport_bind_status → airport_organization_get → airport_organization_bind
case "airport_bind_status" -> {
    var msg = MessageCodec.parse(payload, AirportBindStatusRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new AirportBindStatusReply(0, 1)));
}
case "airport_organization_get" -> {
    var msg = MessageCodec.parse(payload, AirportOrganizationGetRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new AirportOrganizationGetReply(0, ...)));
}
case "airport_organization_bind" -> {
    var msg = MessageCodec.parse(payload, AirportOrganizationBindRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new AirportOrganizationBindReply(0)));
}

// 上线拓扑:设备主动上报 update_topo(status 通道)
var topo = MessageCodec.parse(payload, UpdateTopoData.class);
topo.data().subDevice();  // 子设备列表(含 domain/type/sub_type)

涉及 SDK 类:AirportBindStatusRequest/Reply、AirportOrganizationGetRequest/Reply、AirportOrganizationBindRequest/Reply、UpdateTopoData、UpdateTopoReplyData

2. 航线任务

通道:services(下发)+ events(进度)

case "flighttask_prepare" -> {
    var msg = MessageCodec.parse(payload, FlighttaskPrepareRequest.class);
    msg.data().flightId();              // 航线 ID
    sendReply(msg.tid(), MessageCodec.toJson(new FlighttaskPrepareReply(0)));
}
case "flighttask_execute" -> {
    var msg = MessageCodec.parse(payload, FlighttaskExecuteRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new FlighttaskExecuteReply(0)));
}
case "flighttask_undo" -> {
    var msg = MessageCodec.parse(payload, FlighttaskUndoRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
// flighttask_pause / flighttask_recovery / return_home / return_home_cancel
// 这 4 个无参数方法复用 NoParameterRequest:
case "flighttask_pause" -> {
    var msg = MessageCodec.parse(payload, NoParameterRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}

// 航线进度事件(events 通道)
case "flighttask_progress" -> {
    var msg = MessageCodec.parse(payload, FlighttaskProgressData.class);
    msg.data().output().status();       // executing / success / failed
    sendEventReply(msg.tid(), 0);
}

涉及 SDK 类:FlighttaskPrepareRequest/Reply、FlighttaskExecuteRequest/Reply、FlighttaskUndoRequest、ReturnHomeReply、FlighttaskProgressData、NoParameterRequest(4 个无参数方法共用)

3. 指令飞行

通道:services + events + drc

case "fly_to_point" -> {
    var msg = MessageCodec.parse(payload, FlyToPointRequest.class);
    msg.data().flyToId();
    msg.data().height();               // 相对起飞点高度
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "takeoff_to_point" -> {
    var msg = MessageCodec.parse(payload, TakeoffToPointRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "payload_authority_grab" -> {
    var msg = MessageCodec.parse(payload, PayloadAuthorityGrabRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
// fly_to_point_stop / flight_authority_grab / drc_mode_exit
// 这 3 个无参数方法复用 NoParameterRequest

// 飞行进度事件
case "fly_to_point_progress" -> {
    var msg = MessageCodec.parse(payload, FlyToPointProgressData.class);
    msg.data().status();                // in_progress / success / failed
    sendEventReply(msg.tid(), 0);
}
case "takeoff_to_point_progress" -> {
    var msg = MessageCodec.parse(payload, TakeoffToPointProgressData.class);
    msg.data().status();
    sendEventReply(msg.tid(), 0);
}

涉及 SDK 类:FlyToPointRequest、TakeoffToPointRequest、PayloadAuthorityGrabRequest、FlyToPointProgressData、TakeoffToPointProgressData、NoParameterRequest(3 个无参数方法共用)

4. 远程控制(DRC 通道)

通道:services(进入 DRC)+ drc(摇杆控制)

// 进入 DRC 模式(services 通道)
case "drc_mode_enter" -> {
    var msg = MessageCodec.parse(payload, DrcModeEnterRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}

// DRC 通道消息(topic: thing/product/{sn}/drc/down)
case "drone_control" -> {
    var msg = MessageCodec.parse(payload, DroneControlRequest.class);
    msg.data().joyStickX();      // 横滚 x
    msg.data().joyStickY();      // 俯仰 y
    msg.data().joyStickH();      // 高度 h
    msg.data().joyStickW();      // 偏航 w
    msg.data().seq();            // 序列号
}

涉及 SDK 类:DrcModeEnterRequest、DroneControlRequest/Reply

5. 相机与负载管理

通道:services

case "camera_photo_take" -> {
    var msg = MessageCodec.parse(payload, CameraPhotoTakeRequest.class);
    msg.data().payloadIndex();          // 负载索引
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "camera_recording_start" -> {
    var msg = MessageCodec.parse(payload, CameraRecordingStartRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "camera_recording_stop" -> {
    var msg = MessageCodec.parse(payload, CameraRecordingStopRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}

涉及 SDK 类:CameraPhotoTakeRequest、CameraRecordingStartRequest、CameraRecordingStopRequest

6. 直播管理

通道:services

case "live_start_push" -> {
    var msg = MessageCodec.parse(payload, LiveStartPushRequest.class);
    msg.data().url();                  // RTMP/RTSP 推流地址
    msg.data().videoIndex();           // 视频流索引
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "live_stop_push" -> {
    var msg = MessageCodec.parse(payload, LiveStopPushRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "live_set_quality" -> {
    var msg = MessageCodec.parse(payload, LiveSetQualityRequest.class);
    msg.data().quality();              // 清晰度
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "live_lens_change" -> {
    var msg = MessageCodec.parse(payload, LiveLensChangeRequest.class);
    msg.data().lens();                 // 镜头类型
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}

涉及 SDK 类:LiveStartPushRequest、LiveStopPushRequest、LiveSetQualityRequest、LiveLensChangeRequest

7. 媒体管理

通道:requests(STS 凭证)+ events(上传回调)

// 获取 STS 临时凭证(requests 通道)
case "storage_config_get" -> {
    var msg = MessageCodec.parse(payload, StorageConfigGetRequest.class);
    var reply = new StorageConfigGetReply(0, new StorageConfigGetReply.Output(
        "bucket", "endpoint", "object-key-prefix/", credentials));
    sendReply(msg.tid(), MessageCodec.toJson(reply));
}

// 媒体上传回调(events 通道)
case "file_upload_callback" -> {
    var msg = MessageCodec.parse(payload, FileUploadCallbackData.class);
    msg.data().file().objectKey();     // 对象存储键
    sendEventReply(msg.tid(), 0);
}

涉及 SDK 类:StorageConfigGetRequest/Reply(含 Output 内嵌 STS 凭证结构)、FileUploadCallbackData

8. 固件升级与日志管理

通道:services(无参方法)+ events(进度)

case "ota_create" -> {
    var msg = MessageCodec.parse(payload, OtaCreateRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new OtaCreateReply(0)));
}

// 固件升级进度(events 通道)
case "ota_progress" -> {
    var msg = MessageCodec.parse(payload, OtaProgressData.class);
    msg.data().progress();            // 0-100
    sendEventReply(msg.tid(), 0);
}

// 远程日志(services 通道)
case "fileupload_list" -> {
    var msg = MessageCodec.parse(payload, FileUploadListRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new FileUploadListReply(0, List.of())));
}
case "fileupload_start" -> {
    var msg = MessageCodec.parse(payload, FileUploadStartRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "fileupload_update" -> {
    var msg = MessageCodec.parse(payload, FileUploadUpdateRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}

// 日志上传进度(events 通道)
case "fileupload_progress" -> {
    var msg = MessageCodec.parse(payload, FileuploadProgressData.class);
    msg.data().progress();
    sendEventReply(msg.tid(), 0);
}

涉及 SDK 类:OtaCreateRequest/Reply、OtaProgressData、FileUploadListRequest/Reply、FileUploadStartRequest、FileUploadUpdateRequest、FileuploadProgressData

9. 远程调试

通道:services(无参数指令)+ events(进度上报)

// 11 个无参数远程调试指令复用 NoParameterRequest:
case "drone_open", "drone_close", "device_reboot",
     "cover_open", "cover_close",
     "charge_open", "charge_close",
     "putter_open", "putter_close",
     "drone_format", "device_format" -> {
    var msg = MessageCodec.parse(payload, NoParameterRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}

// 远程调试进度上报(events 通道,与指令同名)
case "drone_open" -> {
    var msg = MessageCodec.parse(payload, DebugProgressData.class);
    msg.data().status();
    sendEventReply(msg.tid(), 0);
}

涉及 SDK 类:NoParameterRequest(11 个无参数指令共用)、DebugProgressData、DebugProgressStatus

10. AI 目标识别

通道:services + events

case "target_detect_open" -> {
    var msg = MessageCodec.parse(payload, TargetDetectOpenRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
// target_detect_close / target_tracking_close 复用 NoParameterRequest
case "target_detect_close" -> {
    var msg = MessageCodec.parse(payload, NoParameterRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}
case "select_tracking_target" -> {
    var msg = MessageCodec.parse(payload, SelectTrackingTargetRequest.class);
    sendReply(msg.tid(), MessageCodec.toJson(new NoOutputReply()));
}

// AI 事件(events 通道)
case "ai_detect_shoot_notify" -> {
    var msg = MessageCodec.parse(payload, AiDetectShootNotifyData.class);
    msg.data().targets();
    sendEventReply(msg.tid(), 0);
}

涉及 SDK 类:TargetDetectOpenRequest、SelectTrackingTargetRequest、AiDetectShootNotifyData、EvidenceCollectionStatusData、AiserviceIllegalParkingInfoData、NoParameterRequest(2 个无参数方法共用)

11. 设备状态与遥测

通道:thing/product/{sn}/osd(周期推送)+ thing/product/{sn}/state(变化推送)

// 机场 OSD(topic: thing/product/{sn}/osd)
DockOsd dockOsd = MessageCodec.fromJson(payload, DockOsd.class);
dockOsd.modeCode();      // 机巢模式码
dockOsd.networkState();   // 网络状态

// 飞行器 OSD
DroneOsd droneOsd = MessageCodec.fromJson(payload, DroneOsd.class);
droneOsd.modeCode();      // 飞行器模式码
droneOsd.latitude();      // 纬度
droneOsd.height();        // 高度(相对起飞点)

涉及 SDK 类:DockOsd、DroneOsd、RcOsd、OsdField(82 个字段枚举)、StateField(7 个字段枚举)、telemetry/enumtype/ 下 24 个枚举类

12. HMS 告警

通道:events

case "hms" -> {
    var msg = MessageCodec.parse(payload, HmsData.class);
    msg.data().list().forEach(hms -> {
        hms.code();        // HMS 错误码(参见 AutelErrorCode)
        hms.level();       // 告警级别
    });
    sendEventReply(msg.tid(), 0);
}

涉及 SDK 类:HmsData、AutelErrorCode(209 个错误码常量)

13. 属性设置

通道:thing/product/{sn}/property/set

// 属性设置请求(扁平 map 结构,无 properties 包裹)
var request = PropertySetRequest.of(Map.of(
    "distance_limit_status", Map.of("state", 1),
    "takeoff_and_rth_altitude", Map.of("rth_altitude", 100, "takeoff_altitude", 50)
));
String payload = MessageCodec.toJson(request);
// 发到 thing/product/{sn}/property/set

// 属性设置回复(扁平 map 结构)
case "property/set" -> {
    var msg = MessageCodec.parse(payload, PropertySetRequest.class);
    var reply = PropertySetReply.of(Map.of(
        "distance_limit_status", 0    // 0=成功
    ));
    sendReply(msg.tid(), MessageCodec.toJson(reply));
}

涉及 SDK 类:PropertySetRequest、PropertySetReply、PropertySetMethod(15 个属性枚举)

场景二:HTTP API + WebSocket 推送

本场景覆盖 HTTP API 调用与 WebSocket 实时推送。SDK 提供 HTTP 路径常量(HttpApiPath)、HTTP 响应信封(HttpResponseEnvelope<T>)、WebSocket biz_code 枚举(WsBizCode)和推送信封(WsPushMessage<T>),不绑定具体 HTTP/WS 客户端实现。

HTTP 调用(前端 → 平台)

用 HttpApiPath 常量拼接路径(替换 {workspace_id} / {wayline_id} 等占位符),用任意 HTTP 客户端发请求。Autel HTTP API 响应统一信封为 {"code":0,"message":"...","data":{...}},用 HttpResponseEnvelope.parse 一步完成信封解析 + data 反序列化为类型安全 POJO。

// 获取 STS 临时凭证
String path = HttpApiPath.STS.replace("{workspace_id}", workspaceId);
HttpResponse resp = httpClient.post(server + path, body);
var envelope = HttpResponseEnvelope.parse(resp.body(), StorageConfigGetReply.Output.class);
if (envelope.code() == 0) {
    envelope.data().bucket();           // 对象存储桶名
    envelope.data().objectKeyPrefix();  // 上传 key 前缀
} else {
    log.error("STS 获取失败: {} - {}", envelope.code(), envelope.message());
}

WebSocket 推送(平台 → 前端)

用 WsPushMessage.extractBizCode 提取消息类型,再按 WsBizCode 路由,每个 case 调 WsPushMessage.parse 一步完成信封解析 + data 反序列化为类型安全 POJO。

void onWsMessage(String payload) {
    String bizCode = WsPushMessage.extractBizCode(payload);
    switch (WsBizCode.fromCode(bizCode).orElse(null)) {
        case DEVICE_OSD -> {
            var msg = WsPushMessage.parse(payload, DeviceOsdPushData.class);
            msg.data().host().latitude();   // 类型安全,无 cast
        }
        case DEVICE_ONLINE, DEVICE_OFFLINE, DEVICE_UPDATE_TOPO -> {
            var msg = WsPushMessage.parse(payload, WsEmptyData.class);
            // 触发 HTTP 拓扑刷新
            String path = HttpApiPath.DEVICES_TOPOLOGIES.replace("{workspace_id}", workspaceId);
            httpClient.get(server + path);
        }
        case MAP_ELEMENT_CREATE, MAP_ELEMENT_UPDATE, MAP_ELEMENT_DELETE -> {
            var msg = WsPushMessage.parse(payload, MapElementPushData.class);
            // 类型安全访问地图元素
        }
        case MAP_GROUP_REFRESH -> {
            var msg = WsPushMessage.parse(payload, MapGroupRefreshData.class);
            // msg.data().ids() → 按 group_id 调 HTTP 拉取元素列表
        }
        case null -> log.warn("未知 biz_code: {}", bizCode);
    }
}

HTTP 端点按业务域

业务域 路径前缀 端点常量
设备拓扑 /manage/api/v1/workspaces DEVICES_TOPOLOGIES
地图元素 /map/api/v1/workspaces ELEMENT_GROUPS、CREATE_ELEMENT、UPDATE_ELEMENT、DELETE_ELEMENT
媒体管理 /media/api/v1/workspaces FAST_UPLOAD、TINY_FINGERPRINTS、UPLOAD_CALLBACK
存储服务 /storage/api/v1/workspaces STS
航线管理 /wayline/api/v1/workspaces WAYLINES、WAYLINE_URL、UPLOAD_CALLBACK

涉及 SDK 类:HttpApiPath(5 业务域 13 个端点)、HttpResponseEnvelope<T>、WsBizCode(8 个 biz_code)、WsPushMessage<T>、推送 data POJO(DeviceOsdPushData、MapElementPushData、MapGroupRefreshData、WsEmptyData)

航线模板(WPML 生成与解析)

WPML(Waypoint Mission Language)是 Autel 机场使用的航线文件格式,本质是一组 XML 文件打包成的 .kmz(ZIP)。本模块是本地文件工具,不涉及 MQTT/HTTP/WS 协议,生成的 .kmz 可通过「场景一 → 2. 航线任务」上传到云平台再推送给机场执行。

四种模板

模板类 templateType 测区/航点 典型场景
WaypointTemplate waypoint 航点列表 航点飞行(巡检/拍照/录像)
Mapping2dTemplate mapping2d Polygon 测区 二维正射建图
Mapping3dTemplate mapping3d Polygon 测区 三维倾斜摄影
MappingStripTemplate mappingStrip LineString 航带 航带飞行(带状测区)

四个模板均提供 toXml()(生成 template.kml)、toWpml()(派生 waylines.wpml)、toKmz()(打包 KMZ)三种输出方式。高度语义:所有 height 参数均为相对起飞点高度,与 Autel WPML wpml:height 定义一致。

航点飞行模板

String kml = WaypointTemplate.builder()
    .author("John")
    .createTime(System.currentTimeMillis())
    .finishAction(FinishAction.GO_HOME)
    .takeOffSecurityHeight(20)
    .globalTransitionalSpeed(8)
    .globalRTHHeight(100)
    .droneInfo(DroneModel.EVO_MAX_4T)       // EVO Max 4T
    .payloadInfo(CameraModel.FUSION_4T)     // Fusion 4T 相机
    .templateId(0)
    .coordinateMode(CoordinateMode.WGS84)
    .heightMode(HeightMode.EGM96)
    .autoFlightSpeed(7)
    .globalHeight(100)
    .globalWaypointTurnMode(WaypointTurnMode.TO_POINT_AND_STOP_WITH_DISCONTINUITY_CURVATURE)
    .addWaypoint(w -> w.longitude(113.98057).latitude(22.987663).height(100)
        .addActionGroup(ag -> ag
            .actionGroupId(0)
            .actionGroupStartIndex(0)
            .actionGroupEndIndex(0)
            .actionTriggerType(ActionTriggerType.REACH_POINT)
            .addAction(a -> a.actionId(0)
                .actionActuatorFunc(ActionActuatorFunc.TAKE_PHOTO)
                .actionActuatorFuncParam(new TakePhotoParam(0, "point1", "wide", 1)))))
    .addWaypoint(w -> w.longitude(113.99000).latitude(22.987663).height(100))
    .toXml();

// 打包为 .kmz
byte[] kmz = WaypointTemplate.builder()
    /* ... 同上 ... */
    .toKmz();

KMZ 打包与解析

WpmlCodec 提供 XML 序列化、KMZ 打包/解包、POJO 反序列化三类静态方法:

// 1. 打包:XML 字符串 → KMZ 字节流
byte[] kmz = WpmlCodec.toKmz(kml, wpml);

// 2. 解包:KMZ 字节流 → 原始 XML 字符串
KmzContent content = WpmlCodec.fromKmz(kmz);
String kml = content.templateKml();
String wpml = content.waylinesWpml();

// 3. 解析:XML 字符串 → POJO
Kml<Folder> template = WpmlCodec.parseTemplateKml(kml);
Kml<ExecuteFolder> waylines = WpmlCodec.parseWaylinesWpml(wpml);

// 4. 一站式:KMZ 字节流 → POJO 容器
ParsedKmz parsed = WpmlCodec.parseKmz(kmz);
Kml<Folder> t = parsed.template();
Kml<ExecuteFolder> w = parsed.waylines();

涉及 SDK 类

  • 模板入口:WaypointTemplate、Mapping2dTemplate、Mapping3dTemplate、MappingStripTemplate
  • Builder 链:WaypointBuilder、ActionGroupBuilder、ActionBuilder
  • 编解码:WpmlCodec(静态工具类)、WpmlStreamWriter/WpmlOutputFactory
  • 动作参数:ActionActuatorFunc(枚举)、ActionActuatorFuncParam(密封接口)及实现类
  • 枚举:enumtype/ 包下共 23 个枚举(HeightMode、ActionActuatorFunc、FinishAction 等)

诊断工具

SDK 提供以下诊断类,供调用者在运行时排查协议对接问题、校验设备配置、追溯协议来源。

错误码查表:AutelErrorCode

Autel 协议错误码为 6 位数字(如 314001),裸数字无法理解含义。AutelErrorCode 收录 209 个错误码常量,提供运行时查表:

// services_reply 返回 result=314001,查表获取官方描述
var msg = MessageCodec.parse(payload, FlighttaskPrepareReply.class);
int result = msg.data().result();

AutelErrorCode.describe(result).ifPresentOrElse(
    info -> log.error("任务失败: {} ({})", info.description(), info.code()),
    () -> log.error("未知错误码: {}", result)
);
// 输出: 任务失败: 飞行任务下发失败,请稍后重试 (314001)

Topic 路由解析:TopicResolver

从 MQTT topic 字符串中解析出设备 SN、通道类型、消息方向,用于日志分类、消息路由、问题定位。

TopicResolver 仅解析 topic 字符串本身的路由信息,不涉及 payload。method 名称是 MQTT 消息的另一独立维度,应通过 MessageCodec.extractMethod(payload) 从 payload 单独提取, 与 topic 解析解耦:

void onMessage(String topic, String payload) {
    TopicInfo info = TopicResolver.resolve(topic);
    String method = MessageCodec.extractMethod(payload);  // 独立维度,单独提取

    log.info("[{}] {} {} → {}",
        info.direction(),   // DOWN(云→设备)/ UP(设备→云)
        info.channel(),     // SERVICES / EVENTS / DRC_UP / ...
        info.deviceSn(),    // 设备 SN
        method);            // fly_to_point

    switch (info.channel()) {
        case SERVICES -> handleServices(info.deviceSn(), method, payload);
        case EVENTS   -> handleEvents(info.deviceSn(), method, payload);
        case DRC_UP   -> handleDrcUp(info.deviceSn(), method, payload);
        case null     -> log.warn("未知通道: {}", topic);
    }
}

设备兼容性校验:DeviceCompatibility

在配置设备组合前校验机场-飞行器或遥控器-飞行器是否兼容,避免下发不支持的指令组合:

// 校验 EVO Nest + EVO Max 4T 是否兼容(true)
boolean ok = DeviceCompatibility.isCompatible(DockModel.EVO_NEST, DroneModel.EVO_MAX_4T);

// 校验 Autel Dragonfish Nest + EVO Max 4T 是否兼容(false,Dragonfish Nest 配套 Dragonfish 飞行器)
boolean ok = DeviceCompatibility.isCompatible(DockModel.AUTEL_DRAGONFISH_NEST, DroneModel.EVO_MAX_4T);
if (!ok) {
    log.warn("Dragonfish Nest 不支持 EVO Max 系列");
}

协议溯源:@Verified / @Inferred / @DocUrl 注解

三个注解均为 RUNTIME 保留策略,可通过反射在运行时检查任何 POJO 或枚举的验证状态和文档来源:

// 检查某个 POJO 的验证状态
var clazz = FlighttaskPrepareRequest.class;
boolean verified = clazz.isAnnotationPresent(Verified.class);
boolean inferred = clazz.isAnnotationPresent(Inferred.class);

if (verified) {
    String basis = clazz.getAnnotation(Verified.class).basis();
    log.info("{} 已验证: {}", clazz.getSimpleName(), basis);
}
if (inferred) {
    String reason = clazz.getAnnotation(Inferred.class).reason();
    String verifyPoint = clazz.getAnnotation(Inferred.class).verifyPoint();
    log.warn("{} 推断项: {} (待验证: {})", clazz.getSimpleName(), reason, verifyPoint);
}

// 获取 Autel 文档链接
if (clazz.isAnnotationPresent(DocUrl.class)) {
    String url = clazz.getAnnotation(DocUrl.class).value();
    log.info("文档: {}", url);
}

模块概览

包 职责 核心类
annotation/ 文档追溯注解 @DocUrl、@Verified、@Inferred
codec/ JSON 编解码 + 类型安全信封解析 MessageCodec、AutelMessage<T>
protocol/ 协议层:topic/method/envelope/error TopicBuilder、TopicResolver、TopicChannel、ServiceMethod/EventMethod/DrcMethod、AutelErrorCode
command/ 指令 POJO:5 通道 service/、drc/、event/、property/、request/、status/
model/ 设备型号/兼容性 DeviceModel、DroneModel、DockModel、ControllerModel、CameraModel、PayloadModel、DeviceCompatibility
telemetry/ OSD/State 遥测 DockOsd、DroneOsd、RcOsd、OsdField、StateField + 24 个枚举类
wayline/ 航线模板(WPML 生成/解析) WaypointTemplate、Mapping2d/3d/StripTemplate、WpmlCodec + 23 个枚举
http/ HTTP 路径常量+响应信封 HttpApiPath、HttpResponseEnvelope<T>
websocket/ WebSocket biz_code+推送 WsBizCode、WsPushMessage<T> + data POJO

设备型号支持

SDK 覆盖 Autel Cloud API 全部 13 款设备型号:

设备大类 枚举 型号
无人机(domain=0) DroneModel EVO Max 4T (0-11000-0)、EVO Max 4N (0-11000-1)
相机(domain=1, camera) CameraModel Fusion 4T (1-10052-0)、Fusion 4N (1-10053-0)、EVO Nest Camera (1-10165-0)
功能负载(domain=1, payload) PayloadModel 抛投器 (1-10301-0)、Tracer (1-10301-0)、喊话器 (1-10305-0)
遥控器(domain=2) ControllerModel Smart Controller V3 (2-20119-0)、Ground Control Station (2-20120-0)
机巢(domain=3) DockModel Autel Virtual Nest (3-30000-0)、EVO Nest (3-30001-0)、Autel Dragonfish Nest (3-30002-0)

设备型号三元组 (domain, type, sub_type) 对齐 Autel Cloud API 产品支持页。

验证状态说明

  • @Verified:已通过 Autel 官方文档核实
  • @Inferred:基于 Autel 文档推断或协议惯例推断,待真机验证
  • 详见各 POJO 文件注解

当前 @Inferred 待验证项(完整清单见各源文件 @Inferred 注解):

  • WsBizCode.DEVICE_OSD — Autel 文档未直接列出 device_osd biz_code,参考 DJI 推断
  • PayloadModel.PAYLOAD_DROP_SYSTEM / AIRBORNE_PILOT_POSITIONING — Autel 官方产品表格 (1,10301,0) 三元组歧义,待官方澄清

文档索引

交流沟通

微信二维码      技术交流群

  • 左侧:扫码添加好友
  • 右侧:扫码加入技术交流群

License

Apache License 2.0 (详见 LICENSE)

About

Autel Cloud API SDK 是将 Autel 上云协议的常量与数据结构以纯 Java 类型(record + enum)表达的类型安全 POJO 库,作为第三方平台对接 Autel 机场与遥控器的协议定义层 + 航线工具套件单一真相源,消除协议定义的重复维护。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages