diff --git a/src/main/java/com/ruoyi/device/controller/AircraftFlyController.java b/src/main/java/com/ruoyi/device/controller/AircraftFlyController.java index 6532013..5b1b3cb 100644 --- a/src/main/java/com/ruoyi/device/controller/AircraftFlyController.java +++ b/src/main/java/com/ruoyi/device/controller/AircraftFlyController.java @@ -100,20 +100,32 @@ public class AircraftFlyController extends BaseController /** * 无人机起飞接口 * - * @param dockId 机场ID - * @return 起飞响应(任务ID和任务状态) + * @param sn 机场SN号 + * @return 起飞响应 */ - @Operation(summary = "无人机起飞", description = "控制指定机场的无人机执行起飞操作,返回任务ID和当前任务状态") - @PostMapping("/takeoff/{dockId}") - public R takeoff( - @Parameter(description = "机场ID", required = true, example = "1") - @PathVariable("dockId") Long dockId) + @Operation(summary = "无人机起飞", description = "控制指定机场的无人机执行起飞操作") + @PostMapping("/takeoff/{sn}") + public R takeoff( + @Parameter(description = "机场SN号", required = true, example = "THJSQ03B2309DN7VQN43") + @PathVariable("sn") String sn) { - // TODO: 实现起飞逻辑 - DroneTakeoffResponseVO vo = new DroneTakeoffResponseVO(); - vo.setTaskId(1L); - vo.setMissionStatus(DroneMissionStatusEnum.TAKING_OFF); - return R.ok(vo); + log.info("收到无人机起飞请求: sn={}", sn); + + try { + CompletableFuture future = machineCommandManager.executeCommand(sn, CommandType.TAKE_OFF); + CommandResult result = future.get(); + + if (result.isSuccess()) { + log.info("无人机起飞成功: sn={}", sn); + return R.ok("起飞命令执行成功"); + } else { + log.error("无人机起飞失败: sn={}, reason={}", sn, result.getErrorMessage()); + return R.fail("起飞命令执行失败: " + result.getErrorMessage()); + } + } catch (Exception e) { + log.error("无人机起飞异常: sn={}", sn, e); + return R.fail("起飞命令执行异常: " + e.getMessage()); + } } /** @@ -286,4 +298,35 @@ public class AircraftFlyController extends BaseController return R.fail("回舱命令执行异常: " + e.getMessage()); } } + + /** + * 无人机返航接口 + * + * @param sn 机场SN号 + * @return 返航响应 + */ + @Operation(summary = "无人机返航", description = "控制指定机场的无人机执行返航操作") + @PostMapping("/return-home/{sn}") + public R returnHome( + @Parameter(description = "机场SN号", required = true, example = "THJSQ03B2309DN7VQN43") + @PathVariable("sn") String sn) + { + log.info("收到无人机返航请求: sn={}", sn); + + try { + CompletableFuture future = machineCommandManager.executeCommand(sn, CommandType.RETURN_HOME); + CommandResult result = future.get(); + + if (result.isSuccess()) { + log.info("无人机返航成功: sn={}", sn); + return R.ok("返航命令执行成功"); + } else { + log.error("无人机返航失败: sn={}, reason={}", sn, result.getErrorMessage()); + return R.fail("返航命令执行失败: " + result.getErrorMessage()); + } + } catch (Exception e) { + log.error("无人机返航异常: sn={}", sn, e); + return R.fail("返航命令执行异常: " + e.getMessage()); + } + } } \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/TuohengVendorConfig.java b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/TuohengVendorConfig.java index bee490f..11a1fe6 100644 --- a/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/TuohengVendorConfig.java +++ b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/TuohengVendorConfig.java @@ -65,8 +65,7 @@ public class TuohengVendorConfig implements VendorConfig { case RETURN_HOME: // 返航前置条件:无人机飞行中 - return droneState == DroneState.FLYING - || droneState == DroneState.ARRIVED; + return true; default: return true; @@ -113,6 +112,18 @@ public class TuohengVendorConfig implements VendorConfig { .setTimeout(60000); transactionMap.put(coverCloseTransaction.getCommandType(), coverCloseTransaction); + // 返航命令 + Transaction returnHomeTransaction = new Transaction("返航", CommandType.RETURN_HOME) + .root(new com.ruoyi.device.domain.impl.machine.vendor.tuoheng.instruction.TuohengReturnHomeInstruction()) + .setTimeout(15000); + transactionMap.put(returnHomeTransaction.getCommandType(), returnHomeTransaction); + + // 起飞命令 + Transaction takeOffTransaction = new Transaction("起飞", CommandType.TAKE_OFF) + .root(new com.ruoyi.device.domain.impl.machine.vendor.tuoheng.instruction.TuohengTakeOffInstruction()) + .setTimeout(300000); + transactionMap.put(takeOffTransaction.getCommandType(), takeOffTransaction); + log.info("拓恒厂家配置初始化完成,共配置{}个命令", transactionMap.size()); } } \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengReturnHomeInstruction.java b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengReturnHomeInstruction.java new file mode 100644 index 0000000..8763c3d --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengReturnHomeInstruction.java @@ -0,0 +1,52 @@ +package com.ruoyi.device.domain.impl.machine.vendor.tuoheng.instruction; + +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.device.domain.impl.machine.instruction.AbstractInstruction; +import com.ruoyi.device.domain.impl.machine.instruction.CallbackConfig; +import com.ruoyi.device.domain.impl.machine.instruction.InstructionContext; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TuohengReturnHomeInstruction extends AbstractInstruction { + + @Override + public String getName() { + return "TUOHENG_RETURN_HOME"; + } + + @Override + public void executeRemoteCall(InstructionContext context) throws Exception { + String sn = context.getSn(); + log.info("发送拓恒无人机返航指令: sn={}", sn); + + JSONObject payload = new JSONObject(); + payload.put("messageID", System.currentTimeMillis()); + payload.put("timestamp", System.currentTimeMillis()); + payload.put("zhilin", "03"); + + String topic = "/topic/v1/airportFly/" + sn + "/control"; + context.getMqttClient().sendMessage(topic, payload.toJSONString()); + log.info("拓恒返航指令发送成功: topic={}, payload={}", topic, payload.toJSONString()); + } + + @Override + public CallbackConfig getMethodCallbackConfig(InstructionContext context) { + String sn = context.getSn(); + return CallbackConfig.builder() + .topic("/topic/v1/airportFly/" + sn + "/control/confirm") + .fieldPath("msg") + .expectedValue("[综管]立即返航指令接收成功") + .timeoutMs(10000) + .build(); + } + + @Override + public CallbackConfig getStateCallbackConfig(InstructionContext context) { + return null; // 返航不需要状态回调 + } + + @Override + public long getTimeoutMs() { + return 15000; + } +} \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengTakeOffInstruction.java b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengTakeOffInstruction.java new file mode 100644 index 0000000..f9cdd6e --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengTakeOffInstruction.java @@ -0,0 +1,54 @@ +package com.ruoyi.device.domain.impl.machine.vendor.tuoheng.instruction; + +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.device.domain.impl.machine.instruction.AbstractInstruction; +import com.ruoyi.device.domain.impl.machine.instruction.CallbackConfig; +import com.ruoyi.device.domain.impl.machine.instruction.InstructionContext; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TuohengTakeOffInstruction extends AbstractInstruction { + + @Override + public String getName() { + return "TUOHENG_TAKE_OFF"; + } + + @Override + public void executeRemoteCall(InstructionContext context) throws Exception { + String sn = context.getSn(); + log.info("发送拓恒无人机起飞指令: sn={}", sn); + + long timestamp = System.currentTimeMillis(); + + JSONObject param = new JSONObject(); + param.put("airlineFileUrl", "http://45.120.103.238:8899/waypoint/default.waypoints"); + param.put("flyBatteryMin", 0.3); + param.put("isMustFly", 1); + + JSONObject payload = new JSONObject(); + payload.put("messageID", String.valueOf(timestamp)); + payload.put("timestamp", timestamp); + payload.put("action", "airlineFlight"); + payload.put("param", param); + + String topic = "/topic/v1/airportFly/" + sn + "/control"; + context.getMqttClient().sendMessage(topic, payload.toJSONString()); + log.info("拓恒起飞指令发送成功: topic={}, payload={}", topic, payload.toJSONString()); + } + + @Override + public CallbackConfig getMethodCallbackConfig(InstructionContext context) { + return null; + } + + @Override + public CallbackConfig getStateCallbackConfig(InstructionContext context) { + return null; + } + + @Override + public long getTimeoutMs() { + return 300000; + } +} \ No newline at end of file