From a6b37bd26964c6f46fd798c053ec4bb3690254f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E5=B0=8F=E4=BA=91?= Date: Wed, 28 Jan 2026 13:57:03 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=81=E7=A7=BBMQTT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 + .../device/domain/impl/djimqtt/README.md | 120 +++++++ .../djimqtt/callback/IDockDataCallback.java | 18 + .../djimqtt/callback/IDroneDataCallback.java | 18 + .../djimqtt/config/DjiMqttProperties.java | 66 ++++ .../djimqtt/example/DjiMqttUsageExample.java | 116 ++++++ .../handler/DjiMqttMessageHandler.java | 216 ++++++++++++ .../impl/djimqtt/model/DjiMqttMessage.java | 43 +++ .../domain/impl/djimqtt/model/DockData.java | 291 ++++++++++++++++ .../domain/impl/djimqtt/model/DroneData.java | 329 ++++++++++++++++++ .../djimqtt/model/dock/AirConditioner.java | 27 ++ .../djimqtt/model/dock/BackupBattery.java | 33 ++ .../djimqtt/model/dock/DockBatteryDetail.java | 39 +++ .../dock/DroneBatteryMaintenanceInfo.java | 41 +++ .../djimqtt/model/dock/DroneChargeState.java | 27 ++ .../impl/djimqtt/model/dock/NetworkState.java | 33 ++ .../impl/djimqtt/model/dock/WirelessLink.java | 75 ++++ .../djimqtt/model/drone/BatteryDetail.java | 75 ++++ .../impl/djimqtt/model/drone/BatteryInfo.java | 47 +++ .../impl/djimqtt/model/drone/CameraInfo.java | 167 +++++++++ .../impl/djimqtt/model/drone/CenterNode.java | 27 ++ .../model/drone/DistanceLimitStatus.java | 33 ++ .../djimqtt/model/drone/IrMeteringArea.java | 57 +++ .../djimqtt/model/drone/IrMeteringPoint.java | 33 ++ .../impl/djimqtt/model/drone/LeafNode.java | 33 ++ .../model/drone/LiveviewWorldRegion.java | 39 +++ .../djimqtt/model/drone/MaintainStatus.java | 23 ++ .../model/drone/MaintainStatusItem.java | 45 +++ .../model/drone/ObstacleAvoidance.java | 33 ++ .../djimqtt/model/drone/PositionState.java | 39 +++ .../impl/djimqtt/model/drone/StorageInfo.java | 27 ++ .../djimqtt/model/drone/TemperaturePoint.java | 33 ++ .../djimqtt/model/drone/WirelessLinkTopo.java | 35 ++ .../djimqtt/service/DjiMqttClientService.java | 159 +++++++++ src/main/resources/bootstrap.yml | 21 ++ 35 files changed, 2425 insertions(+) create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/README.md create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/callback/IDockDataCallback.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/callback/IDroneDataCallback.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/config/DjiMqttProperties.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/example/DjiMqttUsageExample.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/handler/DjiMqttMessageHandler.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DjiMqttMessage.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DockData.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DroneData.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/AirConditioner.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/BackupBattery.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DockBatteryDetail.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DroneBatteryMaintenanceInfo.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DroneChargeState.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/NetworkState.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/WirelessLink.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/BatteryDetail.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/BatteryInfo.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/CameraInfo.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/CenterNode.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/DistanceLimitStatus.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/IrMeteringArea.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/IrMeteringPoint.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/LeafNode.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/LiveviewWorldRegion.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/MaintainStatus.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/MaintainStatusItem.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/ObstacleAvoidance.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/PositionState.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/StorageInfo.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/TemperaturePoint.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/WirelessLinkTopo.java create mode 100644 src/main/java/com/ruoyi/device/domain/impl/djimqtt/service/DjiMqttClientService.java diff --git a/pom.xml b/pom.xml index ea47435..b6a0a18 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,13 @@ provided + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + 1.2.5 + + diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/README.md b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/README.md new file mode 100644 index 0000000..bd935c8 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/README.md @@ -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 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 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` 获取完整示例。 diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/callback/IDockDataCallback.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/callback/IDockDataCallback.java new file mode 100644 index 0000000..9fb14d6 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/callback/IDockDataCallback.java @@ -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); +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/callback/IDroneDataCallback.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/callback/IDroneDataCallback.java new file mode 100644 index 0000000..4bb7f74 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/callback/IDroneDataCallback.java @@ -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); +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/config/DjiMqttProperties.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/config/DjiMqttProperties.java new file mode 100644 index 0000000..4be0041 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/config/DjiMqttProperties.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/example/DjiMqttUsageExample.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/example/DjiMqttUsageExample.java new file mode 100644 index 0000000..9838ea6 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/example/DjiMqttUsageExample.java @@ -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); + } + } +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/handler/DjiMqttMessageHandler.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/handler/DjiMqttMessageHandler.java new file mode 100644 index 0000000..e6489c6 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/handler/DjiMqttMessageHandler.java @@ -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 droneDataCallbacks = new ArrayList<>(); + + /** + * 机场数据回调列表 + */ + private final List 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> 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> 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> 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(); + } +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DjiMqttMessage.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DjiMqttMessage.java new file mode 100644 index 0000000..52d529e --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DjiMqttMessage.java @@ -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 { + + /** + * 事务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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DockData.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DockData.java new file mode 100644 index 0000000..39551a3 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DockData.java @@ -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 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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DroneData.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DroneData.java new file mode 100644 index 0000000..1b359ee --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/DroneData.java @@ -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 rawData; + + // ========== 基础信息 ========== + + /** + * 飞行器图传连接质量最好的网关SN + */ + @JsonProperty("best_link_gateway") + private String bestLinkGateway; + + /** + * 图传连接拓扑 + */ + @JsonProperty("wireless_link_topo") + private WirelessLinkTopo wirelessLinkTopo; + + /** + * 飞行器相机信息 + */ + @JsonProperty("cameras") + private List 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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/AirConditioner.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/AirConditioner.java new file mode 100644 index 0000000..09ba8ce --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/AirConditioner.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/BackupBattery.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/BackupBattery.java new file mode 100644 index 0000000..e703140 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/BackupBattery.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DockBatteryDetail.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DockBatteryDetail.java new file mode 100644 index 0000000..3b271e3 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DockBatteryDetail.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DroneBatteryMaintenanceInfo.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DroneBatteryMaintenanceInfo.java new file mode 100644 index 0000000..f7992b3 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DroneBatteryMaintenanceInfo.java @@ -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 batteries; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DroneChargeState.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DroneChargeState.java new file mode 100644 index 0000000..683de78 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/DroneChargeState.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/NetworkState.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/NetworkState.java new file mode 100644 index 0000000..1a74135 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/NetworkState.java @@ -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-4G,2-以太网 + */ + @JsonProperty("type") + private Integer type; + + /** + * 网络质量:0-无信号,1-差,2-较差,3-一般,4-较好,5-好 + */ + @JsonProperty("quality") + private Integer quality; + + /** + * 网络速率(KB/s) + */ + @JsonProperty("rate") + private Float rate; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/WirelessLink.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/WirelessLink.java new file mode 100644 index 0000000..b285fd1 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/dock/WirelessLink.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/BatteryDetail.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/BatteryDetail.java new file mode 100644 index 0000000..4bce2c6 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/BatteryDetail.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/BatteryInfo.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/BatteryInfo.java new file mode 100644 index 0000000..a0f7d20 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/BatteryInfo.java @@ -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 batteries; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/CameraInfo.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/CameraInfo.java new file mode 100644 index 0000000..58d8779 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/CameraInfo.java @@ -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 photoStorageSettings; + + /** + * 视频存储设置集合 + */ + @JsonProperty("video_storage_settings") + private List 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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/CenterNode.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/CenterNode.java new file mode 100644 index 0000000..4ef0532 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/CenterNode.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/DistanceLimitStatus.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/DistanceLimitStatus.java new file mode 100644 index 0000000..8a02845 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/DistanceLimitStatus.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/IrMeteringArea.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/IrMeteringArea.java new file mode 100644 index 0000000..f330556 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/IrMeteringArea.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/IrMeteringPoint.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/IrMeteringPoint.java new file mode 100644 index 0000000..b111799 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/IrMeteringPoint.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/LeafNode.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/LeafNode.java new file mode 100644 index 0000000..fd0a8f6 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/LeafNode.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/LiveviewWorldRegion.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/LiveviewWorldRegion.java new file mode 100644 index 0000000..0aaa130 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/LiveviewWorldRegion.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/MaintainStatus.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/MaintainStatus.java new file mode 100644 index 0000000..21962a3 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/MaintainStatus.java @@ -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 maintainStatusArray; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/MaintainStatusItem.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/MaintainStatusItem.java new file mode 100644 index 0000000..cf5afe3 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/MaintainStatusItem.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/ObstacleAvoidance.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/ObstacleAvoidance.java new file mode 100644 index 0000000..20aff06 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/ObstacleAvoidance.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/PositionState.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/PositionState.java new file mode 100644 index 0000000..24cca01 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/PositionState.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/StorageInfo.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/StorageInfo.java new file mode 100644 index 0000000..9b86afc --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/StorageInfo.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/TemperaturePoint.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/TemperaturePoint.java new file mode 100644 index 0000000..fcf557b --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/TemperaturePoint.java @@ -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; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/WirelessLinkTopo.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/WirelessLinkTopo.java new file mode 100644 index 0000000..675f20d --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/model/drone/WirelessLinkTopo.java @@ -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 secretCode; + + /** + * 飞行器对频信息 + */ + @JsonProperty("center_node") + private CenterNode centerNode; + + /** + * 当前连接的机场或遥控器对频信息 + */ + @JsonProperty("leaf_nodes") + private List leafNodes; +} diff --git a/src/main/java/com/ruoyi/device/domain/impl/djimqtt/service/DjiMqttClientService.java b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/service/DjiMqttClientService.java new file mode 100644 index 0000000..8ac6054 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/djimqtt/service/DjiMqttClientService.java @@ -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(); + } +} diff --git a/src/main/resources/bootstrap.yml b/src/main/resources/bootstrap.yml index 2ca5c1c..c9b63f8 100644 --- a/src/main/resources/bootstrap.yml +++ b/src/main/resources/bootstrap.yml @@ -34,3 +34,24 @@ device: # 匹配这些正则表达式的设备将被跳过,不进行同步 # 当前配置:过滤所有以 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 \ No newline at end of file