迁移MQTT

This commit is contained in:
孙小云 2026-01-28 13:57:03 +08:00
parent a205823773
commit a6b37bd269
35 changed files with 2425 additions and 0 deletions

View File

@ -105,6 +105,13 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- Eclipse Paho MQTT Client -->
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -0,0 +1,120 @@
# DJI MQTT 模块使用说明
## 概述
本模块实现了大疆MQTT消息的接收和处理功能采用共享订阅方式支持多实例部署。
## 功能特性
- ✅ 自动连接和重连
- ✅ 共享订阅(多实例部署时只有一个实例消费消息)
- ✅ 自动区分无人机和机场数据
- ✅ 回调接口设计使用者无需关心osd和state的区别
- ✅ 完整的数据模型定义
- ✅ 原始数据保留rawData字段
## 架构设计
```
DjiMqttClientService (MQTT客户端)
DjiMqttMessageHandler (消息处理器)
IDroneDataCallback / IDockDataCallback (回调接口)
使用者实现
```
## 配置说明
`bootstrap.yml` 中配置:
```yaml
dji:
mqtt:
host: mqtt.t-aaron.com
port: 10883
version: 5
client-id: ThingsBoard_gateway
username: admin
password: admin
connection-timeout: 30
keep-alive-interval: 60
auto-reconnect: true
clean-session: false
```
## 使用方法
### 1. 注入消息处理器
```java
@Autowired
private DjiMqttMessageHandler messageHandler;
```
### 2. 实现回调接口
```java
// 无人机数据回调
messageHandler.registerDroneDataCallback(new IDroneDataCallback() {
@Override
public void onDroneData(DroneData droneData) {
// 处理无人机数据
String sn = droneData.getDeviceSn();
Double latitude = droneData.getLatitude();
Double longitude = droneData.getLongitude();
// 访问原始数据
Map<String, Object> rawData = droneData.getRawData();
}
});
// 机场数据回调
messageHandler.registerDockDataCallback(new IDockDataCallback() {
@Override
public void onDockData(DockData dockData) {
// 处理机场数据
String sn = dockData.getDeviceSn();
Integer modeCode = dockData.getModeCode();
Float temperature = dockData.getTemperature();
// 访问原始数据
Map<String, Object> rawData = dockData.getRawData();
}
});
```
## 数据模型
### DroneData无人机数据
主要字段:
- `deviceSn`: 设备SN
- `messageType`: 消息类型osd/state
- `latitude/longitude`: 位置信息
- `elevation/height`: 高度信息
- `modeCode`: 飞行器状态
- `rawData`: 原始数据(包含所有字段)
### DockData机场数据
主要字段:
- `deviceSn`: 设备SN
- `messageType`: 消息类型osd/state
- `latitude/longitude`: 位置信息
- `modeCode`: 机场状态
- `temperature/humidity`: 环境信息
- `coverState`: 舱盖状态
- `rawData`: 原始数据(包含所有字段)
## 注意事项
1. **部分字段推送**每次MQTT消息可能只包含部分字段使用时需要判空
2. **原始数据访问**:所有字段都保存在`rawData`中可以通过Map访问
3. **共享订阅**:多实例部署时,同一条消息只会被一个实例消费
4. **自动重连**:连接断开后会自动重连
## 示例代码
参考 `DjiMqttUsageExample.java` 获取完整示例。

View File

@ -0,0 +1,18 @@
package com.ruoyi.device.domain.impl.djimqtt.callback;
import com.ruoyi.device.domain.impl.djimqtt.model.DockData;
/**
* 机场数据回调接口
*
* @author ruoyi
*/
public interface IDockDataCallback {
/**
* 处理机场数据
*
* @param dockData 机场数据
*/
void onDockData(DockData dockData);
}

View File

@ -0,0 +1,18 @@
package com.ruoyi.device.domain.impl.djimqtt.callback;
import com.ruoyi.device.domain.impl.djimqtt.model.DroneData;
/**
* 无人机数据回调接口
*
* @author ruoyi
*/
public interface IDroneDataCallback {
/**
* 处理无人机数据
*
* @param droneData 无人机数据
*/
void onDroneData(DroneData droneData);
}

View File

@ -0,0 +1,66 @@
package com.ruoyi.device.domain.impl.djimqtt.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* DJI MQTT配置属性
*
* @author ruoyi
*/
@Data
@Component
@ConfigurationProperties(prefix = "dji.mqtt")
public class DjiMqttProperties {
/**
* MQTT服务器地址
*/
private String host = "mqtt.t-aaron.com";
/**
* MQTT服务器端口
*/
private Integer port = 10883;
/**
* MQTT协议版本
*/
private Integer version = 5;
/**
* 客户端ID
*/
private String clientId = "ThingsBoard_gateway";
/**
* 用户名
*/
private String username = "admin";
/**
* 密码
*/
private String password = "admin";
/**
* 连接超时时间
*/
private Integer connectionTimeout = 30;
/**
* 保持连接时间
*/
private Integer keepAliveInterval = 60;
/**
* 自动重连
*/
private Boolean autoReconnect = true;
/**
* 清除会话
*/
private Boolean cleanSession = false;
}

View File

@ -0,0 +1,116 @@
package com.ruoyi.device.domain.impl.djimqtt.example;
import com.ruoyi.device.domain.impl.djimqtt.callback.IDockDataCallback;
import com.ruoyi.device.domain.impl.djimqtt.callback.IDroneDataCallback;
import com.ruoyi.device.domain.impl.djimqtt.handler.DjiMqttMessageHandler;
import com.ruoyi.device.domain.impl.djimqtt.model.DockData;
import com.ruoyi.device.domain.impl.djimqtt.model.DroneData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* DJI MQTT使用示例
*
* 使用说明
* 1. 注入 DjiMqttMessageHandler
* 2. 实现 IDroneDataCallback IDockDataCallback 接口
* 3. 在应用启动后注册回调
* 4. 在回调方法中处理接收到的数据
*
* @author ruoyi
*/
@Slf4j
@Component
public class DjiMqttUsageExample {
@Autowired
private DjiMqttMessageHandler messageHandler;
/**
* 应用启动后注册回调
*/
@EventListener(ApplicationReadyEvent.class)
public void registerCallbacks() {
// 注册无人机数据回调
messageHandler.registerDroneDataCallback(new IDroneDataCallback() {
@Override
public void onDroneData(DroneData droneData) {
handleDroneData(droneData);
}
});
// 注册机场数据回调
messageHandler.registerDockDataCallback(new IDockDataCallback() {
@Override
public void onDockData(DockData dockData) {
handleDockData(dockData);
}
});
log.info("DJI MQTT回调已注册");
}
/**
* 处理无人机数据
*/
private void handleDroneData(DroneData droneData) {
log.info("收到无人机数据 - SN: {}, Type: {}",
droneData.getDeviceSn(),
droneData.getMessageType());
// 示例处理位置信息
if (droneData.getLatitude() != null && droneData.getLongitude() != null) {
log.info("无人机位置 - 纬度: {}, 经度: {}, 高度: {}",
droneData.getLatitude(),
droneData.getLongitude(),
droneData.getElevation());
}
// 示例处理电池信息从rawData中获取
if (droneData.getRawData() != null && droneData.getRawData().containsKey("battery")) {
Object battery = droneData.getRawData().get("battery");
log.info("无人机电池信息: {}", battery);
}
// 示例处理相机信息
if (droneData.getRawData() != null && droneData.getRawData().containsKey("cameras")) {
Object cameras = droneData.getRawData().get("cameras");
log.info("无人机相机信息: {}", cameras);
}
}
/**
* 处理机场数据
*/
private void handleDockData(DockData dockData) {
log.info("收到机场数据 - SN: {}, Type: {}",
dockData.getDeviceSn(),
dockData.getMessageType());
// 示例处理机场状态
if (dockData.getModeCode() != null) {
log.info("机场状态: {}", dockData.getModeCode());
}
// 示例处理环境信息
if (dockData.getTemperature() != null) {
log.info("机场温度: {}°C, 湿度: {}%",
dockData.getTemperature(),
dockData.getHumidity());
}
// 示例处理舱盖状态
if (dockData.getCoverState() != null) {
log.info("舱盖状态: {}", dockData.getCoverState());
}
// 示例处理飞行器充电状态从rawData中获取
if (dockData.getRawData() != null && dockData.getRawData().containsKey("drone_charge_state")) {
Object chargeState = dockData.getRawData().get("drone_charge_state");
log.info("飞行器充电状态: {}", chargeState);
}
}
}

View File

@ -0,0 +1,216 @@
package com.ruoyi.device.domain.impl.djimqtt.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.device.domain.impl.djimqtt.callback.IDockDataCallback;
import com.ruoyi.device.domain.impl.djimqtt.callback.IDroneDataCallback;
import com.ruoyi.device.domain.impl.djimqtt.model.DjiMqttMessage;
import com.ruoyi.device.domain.impl.djimqtt.model.DockData;
import com.ruoyi.device.domain.impl.djimqtt.model.DroneData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* DJI MQTT消息处理器
*
* @author ruoyi
*/
@Slf4j
@Component
public class DjiMqttMessageHandler {
private final ObjectMapper objectMapper = new ObjectMapper();
/**
* 无人机数据回调列表
*/
private final List<IDroneDataCallback> droneDataCallbacks = new ArrayList<>();
/**
* 机场数据回调列表
*/
private final List<IDockDataCallback> dockDataCallbacks = new ArrayList<>();
/**
* 无人机SN正则表达式根据文档示例1581F6Q8X251C00G04H8
*/
private static final Pattern DRONE_SN_PATTERN = Pattern.compile("^[0-9A-Z]{20}$");
/**
* 机场SN正则表达式根据文档示例7CTXN5K00B0AXM
*/
private static final Pattern DOCK_SN_PATTERN = Pattern.compile("^[0-9A-Z]{14}$");
/**
* 注册无人机数据回调
*
* @param callback 回调接口
*/
public void registerDroneDataCallback(IDroneDataCallback callback) {
if (callback != null && !droneDataCallbacks.contains(callback)) {
droneDataCallbacks.add(callback);
log.info("注册无人机数据回调: {}", callback.getClass().getSimpleName());
}
}
/**
* 注册机场数据回调
*
* @param callback 回调接口
*/
public void registerDockDataCallback(IDockDataCallback callback) {
if (callback != null && !dockDataCallbacks.contains(callback)) {
dockDataCallbacks.add(callback);
log.info("注册机场数据回调: {}", callback.getClass().getSimpleName());
}
}
/**
* 处理MQTT消息
*
* @param topic 主题
* @param payload 消息内容
*/
public void handleMessage(String topic, String payload) {
try {
log.debug("收到MQTT消息 - Topic: {}, Payload: {}", topic, payload);
// 解析设备SN和消息类型
String deviceSn = extractDeviceSnFromTopic(topic);
String messageType = extractMessageTypeFromTopic(topic);
if (deviceSn == null || messageType == null) {
log.warn("无法从Topic解析设备SN或消息类型: {}", topic);
return;
}
// 解析JSON消息
@SuppressWarnings("unchecked")
DjiMqttMessage<Map<String, Object>> message = objectMapper.readValue(
payload,
objectMapper.getTypeFactory().constructParametricType(
DjiMqttMessage.class,
Map.class
)
);
// 判断是无人机还是机场
if (isDroneSn(deviceSn)) {
handleDroneMessage(deviceSn, messageType, message);
} else if (isDockSn(deviceSn)) {
handleDockMessage(deviceSn, messageType, message);
} else {
log.warn("未知的设备SN格式: {}", deviceSn);
}
} catch (Exception e) {
log.error("处理MQTT消息失败 - Topic: {}, Error: {}", topic, e.getMessage(), e);
}
}
/**
* 处理无人机消息
*/
private void handleDroneMessage(String deviceSn, String messageType, DjiMqttMessage<Map<String, Object>> message) {
try {
DroneData droneData = objectMapper.convertValue(message.getData(), DroneData.class);
droneData.setDeviceSn(deviceSn);
droneData.setMessageType(messageType);
droneData.setRawData(message.getData());
log.debug("处理无人机数据 - SN: {}, Type: {}", deviceSn, messageType);
// 通知所有回调
for (IDroneDataCallback callback : droneDataCallbacks) {
try {
callback.onDroneData(droneData);
} catch (Exception e) {
log.error("无人机数据回调执行失败: {}", e.getMessage(), e);
}
}
} catch (Exception e) {
log.error("处理无人机消息失败 - SN: {}, Error: {}", deviceSn, e.getMessage(), e);
}
}
/**
* 处理机场消息
*/
private void handleDockMessage(String deviceSn, String messageType, DjiMqttMessage<Map<String, Object>> message) {
try {
DockData dockData = objectMapper.convertValue(message.getData(), DockData.class);
dockData.setDeviceSn(deviceSn);
dockData.setMessageType(messageType);
dockData.setRawData(message.getData());
log.debug("处理机场数据 - SN: {}, Type: {}", deviceSn, messageType);
// 通知所有回调
for (IDockDataCallback callback : dockDataCallbacks) {
try {
callback.onDockData(dockData);
} catch (Exception e) {
log.error("机场数据回调执行失败: {}", e.getMessage(), e);
}
}
} catch (Exception e) {
log.error("处理机场消息失败 - SN: {}, Error: {}", deviceSn, e.getMessage(), e);
}
}
/**
* 从Topic中提取设备SN
* Topic格式: thing/product/{deviceSn}/osd thing/product/{deviceSn}/state
*/
private String extractDeviceSnFromTopic(String topic) {
if (topic == null) {
return null;
}
String[] parts = topic.split("/");
if (parts.length >= 3) {
return parts[2];
}
return null;
}
/**
* 从Topic中提取消息类型
*/
private String extractMessageTypeFromTopic(String topic) {
if (topic == null) {
return null;
}
String[] parts = topic.split("/");
if (parts.length >= 4) {
return parts[3]; // osd state
}
return null;
}
/**
* 判断是否为无人机SN
*/
private boolean isDroneSn(String sn) {
if (sn == null) {
return false;
}
Matcher matcher = DRONE_SN_PATTERN.matcher(sn);
return matcher.matches();
}
/**
* 判断是否为机场SN
*/
private boolean isDockSn(String sn) {
if (sn == null) {
return false;
}
Matcher matcher = DOCK_SN_PATTERN.matcher(sn);
return matcher.matches();
}
}

View File

@ -0,0 +1,43 @@
package com.ruoyi.device.domain.impl.djimqtt.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* DJI MQTT消息基础结构
*
* @author ruoyi
*/
@Data
public class DjiMqttMessage<T> {
/**
* 事务ID
*/
@JsonProperty("tid")
private String tid;
/**
* 业务ID
*/
@JsonProperty("bid")
private String bid;
/**
* 时间戳
*/
@JsonProperty("timestamp")
private Long timestamp;
/**
* 数据内容
*/
@JsonProperty("data")
private T data;
/**
* 网关设备SN
*/
@JsonProperty("gateway")
private String gateway;
}

View File

@ -0,0 +1,291 @@
package com.ruoyi.device.domain.impl.djimqtt.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.device.domain.impl.djimqtt.model.dock.*;
import com.ruoyi.device.domain.impl.djimqtt.model.drone.MaintainStatus;
import com.ruoyi.device.domain.impl.djimqtt.model.drone.PositionState;
import com.ruoyi.device.domain.impl.djimqtt.model.drone.StorageInfo;
import lombok.Data;
import java.util.Map;
/**
* 机场完整数据从osd和state主题接收
* 注意每次推送可能只包含部分字段
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DockData {
// ========== 元数据 ==========
/**
* 设备SN从topic中解析
*/
private String deviceSn;
/**
* 消息类型osd或state
*/
private String messageType;
/**
* 原始数据用于存储所有字段
*/
private Map<String, Object> rawData;
// ========== 基础信息 ==========
/**
* Home 点有效性0-无效1-有效
*/
@JsonProperty("home_position_is_valid")
private Integer homePositionIsValid;
/**
* 机场朝向角
*/
@JsonProperty("heading")
private Double heading;
/**
* 固件版本
*/
@JsonProperty("firmware_version")
private String firmwareVersion;
/**
* 机场状态
*/
@JsonProperty("mode_code")
private Integer modeCode;
/**
* 机场任务状态
*/
@JsonProperty("flighttask_step_code")
private Integer flighttaskStepCode;
// ========== 位置信息 ==========
/**
* 纬度
*/
@JsonProperty("latitude")
private Double latitude;
/**
* 经度
*/
@JsonProperty("longitude")
private Double longitude;
/**
* 椭球高度
*/
@JsonProperty("height")
private Double height;
// ========== 环境信息 ==========
/**
* 舱内温度摄氏度
*/
@JsonProperty("temperature")
private Float temperature;
/**
* 舱内湿度%RH
*/
@JsonProperty("humidity")
private Float humidity;
/**
* 环境温度摄氏度
*/
@JsonProperty("environment_temperature")
private Float environmentTemperature;
/**
* 风速/
*/
@JsonProperty("wind_speed")
private Float windSpeed;
/**
* 降雨量0-无雨1-小雨2-中雨3-大雨
*/
@JsonProperty("rainfall")
private Integer rainfall;
// ========== 设备状态 ==========
/**
* 舱盖状态0-关闭1-打开2-半开3-舱盖状态异常
*/
@JsonProperty("cover_state")
private Integer coverState;
/**
* 飞行器是否在舱0-舱外1-舱内
*/
@JsonProperty("drone_in_dock")
private Integer droneInDock;
/**
* DRC链路状态0-未连接1-连接中2-已连接
*/
@JsonProperty("drc_state")
private Integer drcState;
/**
* 紧急停止按钮状态0-关闭1-开启
*/
@JsonProperty("emergency_stop_state")
private Integer emergencyStopState;
/**
* 补光灯状态0-关闭1-打开
*/
@JsonProperty("supplement_light_state")
private Integer supplementLightState;
/**
* 机场声光报警状态0-关闭1-开启
*/
@JsonProperty("alarm_state")
private Integer alarmState;
// ========== 电池和电源 ==========
/**
* 飞行器电池保养信息
*/
@JsonProperty("drone_battery_maintenance_info")
private DroneBatteryMaintenanceInfo droneBatteryMaintenanceInfo;
/**
* 飞行器充电状态
*/
@JsonProperty("drone_charge_state")
private DroneChargeState droneChargeState;
/**
* 机场备用电池信息
*/
@JsonProperty("backup_battery")
private BackupBattery backupBattery;
/**
* 电池运行模式1-计划模式2-待命模式
*/
@JsonProperty("battery_store_mode")
private Integer batteryStoreMode;
/**
* 工作电流毫安
*/
@JsonProperty("working_current")
private Float workingCurrent;
/**
* 工作电压毫伏
*/
@JsonProperty("working_voltage")
private Integer workingVoltage;
// ========== 网络和存储 ==========
/**
* 网络状态
*/
@JsonProperty("network_state")
private NetworkState networkState;
/**
* 图传链路
*/
@JsonProperty("wireless_link")
private WirelessLink wirelessLink;
/**
* 存储容量
*/
@JsonProperty("storage")
private StorageInfo storage;
// ========== 空调和配置 ==========
/**
* 机场空调工作状态信息
*/
@JsonProperty("air_conditioner")
private AirConditioner airConditioner;
/**
* 空中回传false-关闭true-开启
*/
@JsonProperty("air_transfer_enable")
private Boolean airTransferEnable;
/**
* 机场静音模式0-非静音模式1-静音模式
*/
@JsonProperty("silent_mode")
private Integer silentMode;
// ========== 保养和固件 ==========
/**
* 保养信息
*/
@JsonProperty("maintain_status")
private MaintainStatus maintainStatus;
/**
* 搜星状态
*/
@JsonProperty("position_state")
private PositionState positionState;
/**
* 机场激活时间(unix 时间戳)
*/
@JsonProperty("activation_time")
private Integer activationTime;
/**
* 固件升级状态0-未升级1-升级中
*/
@JsonProperty("firmware_upgrade_status")
private Integer firmwareUpgradeStatus;
/**
* 固件一致性0-不需要一致性升级1-需要一致性升级
*/
@JsonProperty("compatible_status")
private Integer compatibleStatus;
// ========== 统计信息 ==========
/**
* 机场累计运行时长
*/
@JsonProperty("acc_time")
private Integer accTime;
/**
* 机场累计作业次数
*/
@JsonProperty("job_number")
private Integer jobNumber;
/**
* 首次上电时间毫秒
*/
@JsonProperty("first_power_on")
private Integer firstPowerOn;
}

View File

@ -0,0 +1,329 @@
package com.ruoyi.device.domain.impl.djimqtt.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.device.domain.impl.djimqtt.model.drone.*;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* 无人机完整数据从osd和state主题接收
* 注意每次推送可能只包含部分字段
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DroneData {
// ========== 元数据 ==========
/**
* 设备SN从topic中解析
*/
private String deviceSn;
/**
* 消息类型osd或state
*/
private String messageType;
/**
* 原始数据用于存储所有字段
*/
private Map<String, Object> rawData;
// ========== 基础信息 ==========
/**
* 飞行器图传连接质量最好的网关SN
*/
@JsonProperty("best_link_gateway")
private String bestLinkGateway;
/**
* 图传连接拓扑
*/
@JsonProperty("wireless_link_topo")
private WirelessLinkTopo wirelessLinkTopo;
/**
* 飞行器相机信息
*/
@JsonProperty("cameras")
private List<CameraInfo> cameras;
/**
* 飞行安全数据库版本
*/
@JsonProperty("flysafe_database_version")
private String flysafeDatabaseVersion;
/**
* 离线地图开关false-关闭true-开启
*/
@JsonProperty("offline_map_enable")
private Boolean offlineMapEnable;
// ========== 返航和限制 ==========
/**
* 返航高度模式当前值0-智能高度1-设定高度
*/
@JsonProperty("current_rth_mode")
private Integer currentRthMode;
/**
* 返航高度模式设置值0-智能高度1-设定高度
*/
@JsonProperty("rth_mode")
private Integer rthMode;
/**
* 飞行器避障状态
*/
@JsonProperty("obstacle_avoidance")
private ObstacleAvoidance obstacleAvoidance;
/**
* 是否接近限飞区0-未达到1-接近
*/
@JsonProperty("is_near_area_limit")
private Integer isNearAreaLimit;
/**
* 是否接近设定的限制高度0-未达到1-接近
*/
@JsonProperty("is_near_height_limit")
private Integer isNearHeightLimit;
/**
* 飞行器限高
*/
@JsonProperty("height_limit")
private Integer heightLimit;
/**
* 飞行器限远状态
*/
@JsonProperty("distance_limit_status")
private DistanceLimitStatus distanceLimitStatus;
// ========== 设备状态 ==========
/**
* 飞行器夜航灯状态0-关闭1-打开
*/
@JsonProperty("night_lights_state")
private Integer nightLightsState;
/**
* 飞行器激活时间(unix 时间戳)
*/
@JsonProperty("activation_time")
private Integer activationTime;
/**
* 保养信息
*/
@JsonProperty("maintain_status")
private MaintainStatus maintainStatus;
/**
* 飞行器累计飞行总架次
*/
@JsonProperty("total_flight_sorties")
private Integer totalFlightSorties;
/**
* 飞行器累计飞行总里程
*/
@JsonProperty("total_flight_distance")
private Float totalFlightDistance;
/**
* 飞行器累计飞行航时
*/
@JsonProperty("total_flight_time")
private Float totalFlightTime;
// ========== 位置信息 ==========
/**
* 搜星状态
*/
@JsonProperty("position_state")
private PositionState positionState;
/**
* 存储容量
*/
@JsonProperty("storage")
private StorageInfo storage;
/**
* 当前位置纬度
*/
@JsonProperty("latitude")
private Double latitude;
/**
* 当前位置经度
*/
@JsonProperty("longitude")
private Double longitude;
/**
* 相对起飞点高度
*/
@JsonProperty("elevation")
private Float elevation;
/**
* 绝对高度
*/
@JsonProperty("height")
private Double height;
/**
* Home点纬度
*/
@JsonProperty("home_latitude")
private Double homeLatitude;
/**
* Home点经度
*/
@JsonProperty("home_longitude")
private Double homeLongitude;
/**
* 距离Home点的距离
*/
@JsonProperty("home_distance")
private Float homeDistance;
// ========== 姿态信息 ==========
/**
* 偏航轴角度
*/
@JsonProperty("attitude_head")
private Integer attitudeHead;
/**
* 横滚轴角度
*/
@JsonProperty("attitude_roll")
private Float attitudeRoll;
/**
* 俯仰轴角度
*/
@JsonProperty("attitude_pitch")
private Float attitudePitch;
// ========== 速度和风速 ==========
/**
* 水平速度/
*/
@JsonProperty("horizontal_speed")
private Float horizontalSpeed;
/**
* 垂直速度/
*/
@JsonProperty("vertical_speed")
private Float verticalSpeed;
/**
* 当前风向
*/
@JsonProperty("wind_direction")
private Integer windDirection;
/**
* 风速/
*/
@JsonProperty("wind_speed")
private Float windSpeed;
// ========== 电池信息 ==========
/**
* 飞行器电池信息
*/
@JsonProperty("battery")
private BatteryInfo battery;
/**
* 严重低电量告警百分比
*/
@JsonProperty("serious_low_battery_warning_threshold")
private Integer seriousLowBatteryWarningThreshold;
/**
* 低电量告警百分比
*/
@JsonProperty("low_battery_warning_threshold")
private Integer lowBatteryWarningThreshold;
/**
* 返航预留电量百分比
*/
@JsonProperty("remaining_power_for_return_home")
private Integer remainingPowerForReturnHome;
// ========== 控制和状态 ==========
/**
* 当前控制源
*/
@JsonProperty("control_source")
private String controlSource;
/**
* 固件升级状态0-未升级1-升级中
*/
@JsonProperty("firmware_upgrade_status")
private Integer firmwareUpgradeStatus;
/**
* 固件一致性0-不需要一致性升级1-需要一致性升级
*/
@JsonProperty("compatible_status")
private Integer compatibleStatus;
/**
* 固件版本
*/
@JsonProperty("firmware_version")
private String firmwareVersion;
/**
* 档位
*/
@JsonProperty("gear")
private Integer gear;
/**
* 飞行器状态
*/
@JsonProperty("mode_code")
private Integer modeCode;
/**
* 飞行器进入当前状态的原因
*/
@JsonProperty("mode_code_reason")
private Integer modeCodeReason;
/**
* 航迹ID
*/
@JsonProperty("track_id")
private String trackId;
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.device.domain.impl.djimqtt.model.dock;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 机场空调工作状态信息
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class AirConditioner {
/**
* 机场空调状态
*/
@JsonProperty("air_conditioner_state")
private Integer airConditionerState;
/**
* 剩余等待可切换时间
*/
@JsonProperty("switch_time")
private Integer switchTime;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.device.domain.impl.djimqtt.model.dock;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 机场备用电池信息
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class BackupBattery {
/**
* 备用电池开关0-关闭1-开启
*/
@JsonProperty("switch")
private Integer switchState;
/**
* 备用电池电压毫伏
*/
@JsonProperty("voltage")
private Integer voltage;
/**
* 备用电池温度摄氏度
*/
@JsonProperty("temperature")
private Float temperature;
}

View File

@ -0,0 +1,39 @@
package com.ruoyi.device.domain.impl.djimqtt.model.dock;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 机场电池详细信息
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DockBatteryDetail {
/**
* 电池剩余电量
*/
@JsonProperty("capacity_percent")
private Integer capacityPercent;
/**
* 电池序号0-左电池1-右电池
*/
@JsonProperty("index")
private Integer index;
/**
* 电压毫伏
*/
@JsonProperty("voltage")
private Integer voltage;
/**
* 温度摄氏度
*/
@JsonProperty("temperature")
private Float temperature;
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.device.domain.impl.djimqtt.model.dock;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* 飞行器电池保养信息
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DroneBatteryMaintenanceInfo {
/**
* 保养状态0-无需保养1-待保养2-正在保养
*/
@JsonProperty("maintenance_state")
private Integer maintenanceState;
/**
* 电池保养剩余时间小时
*/
@JsonProperty("maintenance_time_left")
private Integer maintenanceTimeLeft;
/**
* 电池加热保温状态0-未开启1-加热中2-保温中
*/
@JsonProperty("heat_state")
private Integer heatState;
/**
* 电池详细信息
*/
@JsonProperty("batteries")
private List<DockBatteryDetail> batteries;
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.device.domain.impl.djimqtt.model.dock;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 飞行器充电状态
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DroneChargeState {
/**
* 电量百分比
*/
@JsonProperty("capacity_percent")
private Integer capacityPercent;
/**
* 充电状态0-空闲1-充电中
*/
@JsonProperty("state")
private Integer state;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.device.domain.impl.djimqtt.model.dock;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 网络状态
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class NetworkState {
/**
* 网络类型1-4G2-以太网
*/
@JsonProperty("type")
private Integer type;
/**
* 网络质量0-无信号1-2-较差3-一般4-较好5-
*/
@JsonProperty("quality")
private Integer quality;
/**
* 网络速率KB/s
*/
@JsonProperty("rate")
private Float rate;
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.device.domain.impl.djimqtt.model.dock;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 图传链路
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class WirelessLink {
/**
* 飞行器上 Dongle 数量
*/
@JsonProperty("dongle_number")
private Integer dongleNumber;
/**
* 4G 链路连接状态0-断开1-连接
*/
@JsonProperty("4g_link_state")
private Integer fourGLinkState;
/**
* SDR 链路连接状态0-断开1-连接
*/
@JsonProperty("sdr_link_state")
private Integer sdrLinkState;
/**
* 机场的图传链路模式0-SDR 模式1-4G 融合模式
*/
@JsonProperty("link_workmode")
private Integer linkWorkmode;
/**
* SDR 信号质量0-5
*/
@JsonProperty("sdr_quality")
private Integer sdrQuality;
/**
* 总体 4G 信号质量0-5
*/
@JsonProperty("4g_quality")
private Integer fourGQuality;
/**
* 天端 4G 信号质量0-5
*/
@JsonProperty("4g_uav_quality")
private Integer fourGUavQuality;
/**
* 地端 4G 信号质量0-5
*/
@JsonProperty("4g_gnd_quality")
private Integer fourGGndQuality;
/**
* SDR 频段
*/
@JsonProperty("sdr_freq_band")
private Float sdrFreqBand;
/**
* 4G 频段
*/
@JsonProperty("4g_freq_band")
private Float fourGFreqBand;
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 电池详细信息
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class BatteryDetail {
/**
* 电池剩余电量
*/
@JsonProperty("capacity_percent")
private Integer capacityPercent;
/**
* 电池序号
*/
@JsonProperty("index")
private Integer index;
/**
* 电池序列号SN
*/
@JsonProperty("sn")
private String sn;
/**
* 电池类型
*/
@JsonProperty("type")
private Integer type;
/**
* 电池子类型
*/
@JsonProperty("sub_type")
private Integer subType;
/**
* 固件版本
*/
@JsonProperty("firmware_version")
private String firmwareVersion;
/**
* 电池循环次数
*/
@JsonProperty("loop_times")
private Integer loopTimes;
/**
* 电压毫伏
*/
@JsonProperty("voltage")
private Integer voltage;
/**
* 温度摄氏度
*/
@JsonProperty("temperature")
private Float temperature;
/**
* 高电压存储天数
*/
@JsonProperty("high_voltage_storage_days")
private Integer highVoltageStorageDays;
}

View File

@ -0,0 +1,47 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* 飞行器电池信息
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class BatteryInfo {
/**
* 电池的总剩余电量
*/
@JsonProperty("capacity_percent")
private Integer capacityPercent;
/**
* 剩余飞行时间
*/
@JsonProperty("remain_flight_time")
private Integer remainFlightTime;
/**
* 返航所需电量百分比
*/
@JsonProperty("return_home_power")
private Integer returnHomePower;
/**
* 强制降落电量百分比
*/
@JsonProperty("landing_power")
private Integer landingPower;
/**
* 电池详细信息
*/
@JsonProperty("batteries")
private List<BatteryDetail> batteries;
}

View File

@ -0,0 +1,167 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* 飞行器相机信息
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class CameraInfo {
/**
* 剩余拍照张数
*/
@JsonProperty("remain_photo_num")
private Integer remainPhotoNum;
/**
* 剩余录像时间
*/
@JsonProperty("remain_record_duration")
private Integer remainRecordDuration;
/**
* 视频录制时长
*/
@JsonProperty("record_time")
private Integer recordTime;
/**
* 负载编号
*/
@JsonProperty("payload_index")
private String payloadIndex;
/**
* 相机模式0-拍照1-录像2-智能低光3-全景拍照
*/
@JsonProperty("camera_mode")
private Integer cameraMode;
/**
* 拍照状态0-空闲1-拍照中
*/
@JsonProperty("photo_state")
private Integer photoState;
/**
* 录像状态0-空闲1-录像中
*/
@JsonProperty("recording_state")
private Integer recordingState;
/**
* 变焦倍数
*/
@JsonProperty("zoom_factor")
private Float zoomFactor;
/**
* 红外变焦倍数
*/
@JsonProperty("ir_zoom_factor")
private Float irZoomFactor;
/**
* 视场角FOV liveview 中的区域
*/
@JsonProperty("liveview_world_region")
private LiveviewWorldRegion liveviewWorldRegion;
/**
* 照片存储设置集合
*/
@JsonProperty("photo_storage_settings")
private List<String> photoStorageSettings;
/**
* 视频存储设置集合
*/
@JsonProperty("video_storage_settings")
private List<String> videoStorageSettings;
/**
* 广角镜头曝光模式
*/
@JsonProperty("wide_exposure_mode")
private Integer wideExposureMode;
/**
* 广角镜头感光度
*/
@JsonProperty("wide_iso")
private Integer wideIso;
/**
* 广角镜头快门速度
*/
@JsonProperty("wide_shutter_speed")
private Integer wideShutterSpeed;
/**
* 广角镜头曝光值
*/
@JsonProperty("wide_exposure_value")
private Integer wideExposureValue;
/**
* 变焦镜头曝光模式
*/
@JsonProperty("zoom_exposure_mode")
private Integer zoomExposureMode;
/**
* 变焦镜头感光度
*/
@JsonProperty("zoom_iso")
private Integer zoomIso;
/**
* 变焦镜头快门速度
*/
@JsonProperty("zoom_shutter_speed")
private Integer zoomShutterSpeed;
/**
* 变焦镜头曝光值
*/
@JsonProperty("zoom_exposure_value")
private Integer zoomExposureValue;
/**
* 变焦镜头对焦模式
*/
@JsonProperty("zoom_focus_mode")
private Integer zoomFocusMode;
/**
* 变焦镜头对焦值
*/
@JsonProperty("zoom_focus_value")
private Integer zoomFocusValue;
/**
* 红外测温模式
*/
@JsonProperty("ir_metering_mode")
private Integer irMeteringMode;
/**
* 红外测温点
*/
@JsonProperty("ir_metering_point")
private IrMeteringPoint irMeteringPoint;
/**
* 红外测温区域
*/
@JsonProperty("ir_metering_area")
private IrMeteringArea irMeteringArea;
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 飞行器对频信息中心节点
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class CenterNode {
/**
* 扰码信息
*/
@JsonProperty("sdr_id")
private Integer sdrId;
/**
* 设备sn
*/
@JsonProperty("sn")
private String sn;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 飞行器限远状态
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DistanceLimitStatus {
/**
* 是否开启限远0-未设置1-已设置
*/
@JsonProperty("state")
private Integer state;
/**
* 限远距离
*/
@JsonProperty("distance_limit")
private Integer distanceLimit;
/**
* 是否接近设定的限制距离0-未达到1-接近
*/
@JsonProperty("is_near_distance_limit")
private Integer isNearDistanceLimit;
}

View File

@ -0,0 +1,57 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 红外测温区域
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class IrMeteringArea {
/**
* 测温区域左上角点坐标 x
*/
@JsonProperty("x")
private Double x;
/**
* 测温区域左上角点坐标 y
*/
@JsonProperty("y")
private Double y;
/**
* 测温区域宽度
*/
@JsonProperty("width")
private Double width;
/**
* 测温区域高度
*/
@JsonProperty("height")
private Double height;
/**
* 测温区域平均温度
*/
@JsonProperty("aver_temperature")
private Double averTemperature;
/**
* 测温区域最低温度点
*/
@JsonProperty("min_temperature_point")
private TemperaturePoint minTemperaturePoint;
/**
* 测温区域最高温度点
*/
@JsonProperty("max_temperature_point")
private TemperaturePoint maxTemperaturePoint;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 红外测温点
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class IrMeteringPoint {
/**
* 测温点坐标 x
*/
@JsonProperty("x")
private Double x;
/**
* 测温点坐标 y
*/
@JsonProperty("y")
private Double y;
/**
* 测温点的温度
*/
@JsonProperty("temperature")
private Double temperature;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 机场或遥控器对频信息叶子节点
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class LeafNode {
/**
* 扰码信息
*/
@JsonProperty("sdr_id")
private Integer sdrId;
/**
* 设备sn
*/
@JsonProperty("sn")
private String sn;
/**
* 控制源序号
*/
@JsonProperty("control_source_index")
private Integer controlSourceIndex;
}

View File

@ -0,0 +1,39 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 视场角FOV liveview 中的区域
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class LiveviewWorldRegion {
/**
* 左上角的 x 轴起始点
*/
@JsonProperty("left")
private Float left;
/**
* 左上角的 y 轴起始点
*/
@JsonProperty("top")
private Float top;
/**
* 右下角的 x 轴起始点
*/
@JsonProperty("right")
private Float right;
/**
* 右下角的 y 轴起始点
*/
@JsonProperty("bottom")
private Float bottom;
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* 保养信息
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class MaintainStatus {
/**
* 保养信息数组
*/
@JsonProperty("maintain_status_array")
private List<MaintainStatusItem> maintainStatusArray;
}

View File

@ -0,0 +1,45 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 保养信息项
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class MaintainStatusItem {
/**
* 保养状态0-无保养1-有保养
*/
@JsonProperty("state")
private Integer state;
/**
* 上一次保养类型1-飞行器基础保养2-飞行器常规保养3-飞行器深度保养
*/
@JsonProperty("last_maintain_type")
private Integer lastMaintainType;
/**
* 上一次保养时间
*/
@JsonProperty("last_maintain_time")
private Long lastMaintainTime;
/**
* 上一次保养时飞行航时小时
*/
@JsonProperty("last_maintain_flight_time")
private Integer lastMaintainFlightTime;
/**
* 上一次保养时飞行架次
*/
@JsonProperty("last_maintain_flight_sorties")
private Integer lastMaintainFlightSorties;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 飞行器避障状态
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ObstacleAvoidance {
/**
* 水平避障状态0-关闭1-开启
*/
@JsonProperty("horizon")
private Integer horizon;
/**
* 上视避障状态0-关闭1-开启
*/
@JsonProperty("upside")
private Integer upside;
/**
* 下视避障状态0-关闭1-开启
*/
@JsonProperty("downside")
private Integer downside;
}

View File

@ -0,0 +1,39 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 搜星状态
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class PositionState {
/**
* 是否收敛0-未开始1-收敛中2-收敛成功3-收敛失败
*/
@JsonProperty("is_fixed")
private Integer isFixed;
/**
* 搜星档位1-1档2-2档3-3档4-4档5-5档10-RTK fixed
*/
@JsonProperty("quality")
private Integer quality;
/**
* GPS 搜星数量
*/
@JsonProperty("gps_number")
private Integer gpsNumber;
/**
* RTK 搜星数量
*/
@JsonProperty("rtk_number")
private Integer rtkNumber;
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 存储容量
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class StorageInfo {
/**
* 总容量KB
*/
@JsonProperty("total")
private Integer total;
/**
* 已使用容量KB
*/
@JsonProperty("used")
private Integer used;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 温度点
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class TemperaturePoint {
/**
* 温度点坐标 x
*/
@JsonProperty("x")
private Double x;
/**
* 温度点坐标 y
*/
@JsonProperty("y")
private Double y;
/**
* 温度点的温度
*/
@JsonProperty("temperature")
private Double temperature;
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.device.domain.impl.djimqtt.model.drone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* 图传连接拓扑
*
* @author ruoyi
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class WirelessLinkTopo {
/**
* 加密编码
*/
@JsonProperty("secret_code")
private List<Integer> secretCode;
/**
* 飞行器对频信息
*/
@JsonProperty("center_node")
private CenterNode centerNode;
/**
* 当前连接的机场或遥控器对频信息
*/
@JsonProperty("leaf_nodes")
private List<LeafNode> leafNodes;
}

View File

@ -0,0 +1,159 @@
package com.ruoyi.device.domain.impl.djimqtt.service;
import com.ruoyi.device.domain.impl.djimqtt.config.DjiMqttProperties;
import com.ruoyi.device.domain.impl.djimqtt.handler.DjiMqttMessageHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import jakarta.annotation.PreDestroy;
/**
* DJI MQTT客户端服务
* 采用共享订阅方式支持多实例部署
*
* @author ruoyi
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DjiMqttClientService {
private final DjiMqttProperties mqttProperties;
private final DjiMqttMessageHandler messageHandler;
private MqttClient mqttClient;
/**
* 无人机OSD主题共享订阅
*/
private static final String DRONE_OSD_TOPIC = "$share/dji-group/thing/product/+/osd";
/**
* 无人机State主题共享订阅
*/
private static final String DRONE_STATE_TOPIC = "$share/dji-group/thing/product/+/state";
/**
* 应用启动后自动连接
*/
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
connect();
}
/**
* 连接到MQTT服务器
*/
public void connect() {
try {
if (mqttClient != null && mqttClient.isConnected()) {
log.info("MQTT客户端已连接无需重复连接");
return;
}
String broker = String.format("tcp://%s:%d", mqttProperties.getHost(), mqttProperties.getPort());
log.info("开始连接DJI MQTT服务器: {}", broker);
// 创建MQTT客户端
mqttClient = new MqttClient(broker, mqttProperties.getClientId(), new MemoryPersistence());
// 配置连接选项
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(mqttProperties.getUsername());
options.setPassword(mqttProperties.getPassword().toCharArray());
options.setConnectionTimeout(mqttProperties.getConnectionTimeout());
options.setKeepAliveInterval(mqttProperties.getKeepAliveInterval());
options.setAutomaticReconnect(mqttProperties.getAutoReconnect());
options.setCleanSession(mqttProperties.getCleanSession());
// 设置MQTT版本
if (mqttProperties.getVersion() == 5) {
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
log.info("使用MQTT协议版本: 3.1.1");
}
// 设置回调
mqttClient.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
log.error("MQTT连接丢失: {}", cause.getMessage(), cause);
}
@Override
public void messageArrived(String topic, MqttMessage message) {
try {
String payload = new String(message.getPayload());
messageHandler.handleMessage(topic, payload);
} catch (Exception e) {
log.error("处理MQTT消息失败: {}", e.getMessage(), e);
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// 不需要处理发送完成事件
}
});
// 连接
mqttClient.connect(options);
log.info("成功连接到DJI MQTT服务器");
// 订阅主题
subscribe();
} catch (Exception e) {
log.error("连接DJI MQTT服务器失败: {}", e.getMessage(), e);
}
}
/**
* 订阅主题
*/
private void subscribe() {
try {
if (mqttClient == null || !mqttClient.isConnected()) {
log.warn("MQTT客户端未连接无法订阅主题");
return;
}
// 订阅无人机OSD主题共享订阅
mqttClient.subscribe(DRONE_OSD_TOPIC, 1);
log.info("成功订阅主题: {}", DRONE_OSD_TOPIC);
// 订阅无人机State主题共享订阅
mqttClient.subscribe(DRONE_STATE_TOPIC, 1);
log.info("成功订阅主题: {}", DRONE_STATE_TOPIC);
} catch (Exception e) {
log.error("订阅MQTT主题失败: {}", e.getMessage(), e);
}
}
/**
* 断开连接
*/
@PreDestroy
public void disconnect() {
try {
if (mqttClient != null && mqttClient.isConnected()) {
mqttClient.disconnect();
mqttClient.close();
log.info("已断开DJI MQTT连接");
}
} catch (Exception e) {
log.error("断开DJI MQTT连接失败: {}", e.getMessage(), e);
}
}
/**
* 检查连接状态
*/
public boolean isConnected() {
return mqttClient != null && mqttClient.isConnected();
}
}

View File

@ -34,3 +34,24 @@ device:
# 匹配这些正则表达式的设备将被跳过,不进行同步 # 匹配这些正则表达式的设备将被跳过,不进行同步
# 当前配置:过滤所有以 TH 开头的设备 # 当前配置:过滤所有以 TH 开头的设备
exclude-patterns: TH.* exclude-patterns: TH.*
machine:
state:
store:
type: redis # 或 memory,根据部署方式选择
sn:
repository:
type: memory # 或 redis/mysql,根据需求选择
# DJI MQTT配置
dji:
mqtt:
host: mqtt.t-aaron.com
port: 10883
version: 5
client-id: ThingsBoard_gateway
username: admin
password: admin
connection-timeout: 30
keep-alive-interval: 60
auto-reconnect: true
clean-session: false