diff --git a/src/main/java/com/ruoyi/device/controller/AircraftFlyController.java b/src/main/java/com/ruoyi/device/controller/AircraftFlyController.java index 4af4a39..6532013 100644 --- a/src/main/java/com/ruoyi/device/controller/AircraftFlyController.java +++ b/src/main/java/com/ruoyi/device/controller/AircraftFlyController.java @@ -218,4 +218,72 @@ public class AircraftFlyController extends BaseController return R.fail("查询状态失败: " + e.getMessage()); } } + + /** + * 出舱接口 + * + * @param sn 机场SN号 + * @return 出舱响应 + */ + @Operation(summary = "出舱", description = "控制指定机场执行出舱操作") + @PostMapping("/cover-open/{sn}") + public R coverOpen( + @Parameter(description = "机场SN号", required = true, example = "THJSQ03B2309DN7VQN43") + @PathVariable("sn") String sn) + { + log.info("收到出舱请求: sn={}", sn); + + try { + // 调用机器命令管理器执行出舱命令 + CompletableFuture future = machineCommandManager.executeCommand(sn, CommandType.OPEN_COVER); + + // 等待命令执行完成 + 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()); + } + } + + /** + * 回舱接口 + * + * @param sn 机场SN号 + * @return 回舱响应 + */ + @Operation(summary = "回舱", description = "控制指定机场执行回舱操作") + @PostMapping("/cover-close/{sn}") + public R coverClose( + @Parameter(description = "机场SN号", required = true, example = "THJSQ03B2309DN7VQN43") + @PathVariable("sn") String sn) + { + log.info("收到回舱请求: sn={}", sn); + + try { + // 调用机器命令管理器执行回舱命令 + CompletableFuture future = machineCommandManager.executeCommand(sn, CommandType.CLOSE_COVER); + + // 等待命令执行完成 + 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 4c58432..bee490f 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 @@ -101,6 +101,18 @@ public class TuohengVendorConfig implements VendorConfig { .setTimeout(66000); transactionMap.put(powerOffTransaction.getCommandType(), powerOffTransaction); + // 出舱命令 + Transaction coverOpenTransaction = new Transaction("出舱", CommandType.OPEN_COVER) + .root(new com.ruoyi.device.domain.impl.machine.vendor.tuoheng.instruction.TuohengCoverOpenInstruction()) + .setTimeout(60000); + transactionMap.put(coverOpenTransaction.getCommandType(), coverOpenTransaction); + + // 回舱命令 + Transaction coverCloseTransaction = new Transaction("回舱", CommandType.CLOSE_COVER) + .root(new com.ruoyi.device.domain.impl.machine.vendor.tuoheng.instruction.TuohengCoverCloseInstruction()) + .setTimeout(60000); + transactionMap.put(coverCloseTransaction.getCommandType(), coverCloseTransaction); + 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/TuohengCoverCloseInstruction.java b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengCoverCloseInstruction.java new file mode 100644 index 0000000..686eb0b --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengCoverCloseInstruction.java @@ -0,0 +1,61 @@ +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 TuohengCoverCloseInstruction extends AbstractInstruction { + + @Override + public String getName() { + return "TUOHENG_COVER_CLOSE"; + } + + @Override + public void executeRemoteCall(InstructionContext context) throws Exception { + String sn = context.getSn(); + log.info("发送拓恒机场回舱指令: sn={}", sn); + + // 构建MQTT消息 + JSONObject payload = new JSONObject(); + payload.put("messageID", String.valueOf(System.currentTimeMillis())); + payload.put("timestamp", System.currentTimeMillis()); + payload.put("code", "DroneNest"); + payload.put("value", "2"); // 2=回舱 + + String topic = "/topic/v1/airportNest/" + 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) { + String sn = context.getSn(); + + // 监听舱门状态变化(从心跳消息) + return CallbackConfig.builder() + .topic("/topic/v1/heartbeat/" + sn + "/message") + .fieldPath("nestDoor.data.status") + .expectedValue("1") // 1表示关仓 + .timeoutMs(60000) + .build(); + } + + @Override + public long getTimeoutMs() { + return 60000; // 总超时时间60秒 + } +} \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengCoverOpenInstruction.java b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengCoverOpenInstruction.java new file mode 100644 index 0000000..ac601b5 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/impl/machine/vendor/tuoheng/instruction/TuohengCoverOpenInstruction.java @@ -0,0 +1,61 @@ +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 TuohengCoverOpenInstruction extends AbstractInstruction { + + @Override + public String getName() { + return "TUOHENG_COVER_OPEN"; + } + + @Override + public void executeRemoteCall(InstructionContext context) throws Exception { + String sn = context.getSn(); + log.info("发送拓恒机场出舱指令: sn={}", sn); + + // 构建MQTT消息 + JSONObject payload = new JSONObject(); + payload.put("messageID", String.valueOf(System.currentTimeMillis())); + payload.put("timestamp", System.currentTimeMillis()); + payload.put("code", "DroneNest"); + payload.put("value", "1"); // 1=出舱 + + String topic = "/topic/v1/airportNest/" + 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) { + String sn = context.getSn(); + + // 监听舱门状态变化(从心跳消息) + return CallbackConfig.builder() + .topic("/topic/v1/heartbeat/" + sn + "/message") + .fieldPath("nestDoor.data.status") + .expectedValue("0") // 0表示开仓 + .timeoutMs(60000) + .build(); + } + + @Override + public long getTimeoutMs() { + return 60000; // 总超时时间60秒 + } +} \ No newline at end of file