diff --git a/src/main/java/com/qyft/ms/app/controller/TestController.java b/src/main/java/com/qyft/ms/app/controller/TestController.java new file mode 100644 index 0000000..e78853a --- /dev/null +++ b/src/main/java/com/qyft/ms/app/controller/TestController.java @@ -0,0 +1,30 @@ +package com.qyft.ms.app.controller; + +import com.qyft.ms.app.device.status.DeviceStatus; +import com.qyft.ms.system.common.result.Result; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 测试用 + */ +@Tag(name = "测试用") +@RestController +@RequestMapping("/api/test") +@RequiredArgsConstructor +@Slf4j +public class TestController { + private final DeviceStatus deviceStatus; + + @Operation(summary = "启动虚拟模式") + @PostMapping("/virtual") + public Result changeVirtualMode() { + deviceStatus.setVirtual(true); + return Result.success(); + } +} diff --git a/src/main/java/com/qyft/ms/app/core/event/VirtualDeviceCmdResponseEvent.java b/src/main/java/com/qyft/ms/app/core/event/VirtualDeviceCmdResponseEvent.java new file mode 100644 index 0000000..552bc3d --- /dev/null +++ b/src/main/java/com/qyft/ms/app/core/event/VirtualDeviceCmdResponseEvent.java @@ -0,0 +1,16 @@ +package com.qyft.ms.app.core.event; + +import com.qyft.ms.system.model.bo.DeviceCommand; +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class VirtualDeviceCmdResponseEvent extends ApplicationEvent { + private final DeviceCommand cmdToDevice; + + public VirtualDeviceCmdResponseEvent(Object source, DeviceCommand cmdToDevice) { + super(source); + this.cmdToDevice = cmdToDevice; + } + +} diff --git a/src/main/java/com/qyft/ms/app/core/listener/DeviceInitializerListener.java b/src/main/java/com/qyft/ms/app/core/listener/DeviceInitializerListener.java index 5970de6..7b7ee44 100644 --- a/src/main/java/com/qyft/ms/app/core/listener/DeviceInitializerListener.java +++ b/src/main/java/com/qyft/ms/app/core/listener/DeviceInitializerListener.java @@ -27,11 +27,13 @@ public class DeviceInitializerListener { ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); Runnable task = () -> { try { - DeviceCommand overallDeviceStatusGetCommand = DeviceCommandGenerator.overallDeviceStatusGet(); - CommandFuture overallDeviceStatusGetCommandFuture = deviceCommandService.sendCommandNoFront(overallDeviceStatusGetCommand); - overallDeviceStatusGetCommandFuture.getResponseFuture().get(5, TimeUnit.SECONDS); - boolean emergencyStop = overallDeviceStatusGetCommandFuture.getResponseResult().getJSONObject("data").getBool("emergencyStop"); - deviceStatus.setStopPressed(emergencyStop); + if(!deviceStatus.isVirtual()){ + DeviceCommand overallDeviceStatusGetCommand = DeviceCommandGenerator.overallDeviceStatusGet(); + CommandFuture overallDeviceStatusGetCommandFuture = deviceCommandService.sendCommandNoFront(overallDeviceStatusGetCommand); + overallDeviceStatusGetCommandFuture.getResponseFuture().get(5, TimeUnit.SECONDS); + boolean emergencyStop = overallDeviceStatusGetCommandFuture.getResponseResult().getJSONObject("data").getBool("emergencyStop"); + deviceStatus.setStopPressed(emergencyStop); + } scheduler.shutdown(); } catch (Exception e) { log.error("开机获取急停状态失败", e); diff --git a/src/main/java/com/qyft/ms/app/core/listener/VirtualDeviceCmdResponseEventListener.java b/src/main/java/com/qyft/ms/app/core/listener/VirtualDeviceCmdResponseEventListener.java new file mode 100644 index 0000000..c74504f --- /dev/null +++ b/src/main/java/com/qyft/ms/app/core/listener/VirtualDeviceCmdResponseEventListener.java @@ -0,0 +1,20 @@ +package com.qyft.ms.app.core.listener; + +import com.qyft.ms.app.core.event.VirtualDeviceCmdResponseEvent; +import com.qyft.ms.app.service.VirtualDeviceService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class VirtualDeviceCmdResponseEventListener { + private final VirtualDeviceService virtualDeviceService; + + @EventListener + public void handleDeviceTcpMessageEvent(VirtualDeviceCmdResponseEvent event) { + virtualDeviceService.completeCommandResponse(event.getCmdToDevice()); + } +} diff --git a/src/main/java/com/qyft/ms/app/device/status/DeviceStatus.java b/src/main/java/com/qyft/ms/app/device/status/DeviceStatus.java index 33701c6..e1b6cad 100644 --- a/src/main/java/com/qyft/ms/app/device/status/DeviceStatus.java +++ b/src/main/java/com/qyft/ms/app/device/status/DeviceStatus.java @@ -1,6 +1,7 @@ package com.qyft.ms.app.device.status; import cn.hutool.json.JSONObject; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.stereotype.Component; @@ -56,6 +57,11 @@ public class DeviceStatus { */ private volatile boolean stopPressed = false; + /** + * 是否启动虚拟模式 + */ + private boolean virtual = false; + public JSONObject toJSON() { JSONObject json = new JSONObject(); json.putOnce("spraying", spraying); @@ -67,6 +73,7 @@ public class DeviceStatus { json.putOnce("dehumidifierRunning", dehumidifierRunning); json.putOnce("selfTestCompleted", selfTestCompleted); json.putOnce("stopPressed", stopPressed); + json.putOnce("virtual", virtual); return json; } diff --git a/src/main/java/com/qyft/ms/app/service/TestService.java b/src/main/java/com/qyft/ms/app/service/TestService.java new file mode 100644 index 0000000..c75df82 --- /dev/null +++ b/src/main/java/com/qyft/ms/app/service/TestService.java @@ -0,0 +1,13 @@ +package com.qyft.ms.app.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * 测试用 + */ +@Service +@RequiredArgsConstructor +public class TestService { + +} diff --git a/src/main/java/com/qyft/ms/app/service/VirtualDeviceService.java b/src/main/java/com/qyft/ms/app/service/VirtualDeviceService.java new file mode 100644 index 0000000..80135c5 --- /dev/null +++ b/src/main/java/com/qyft/ms/app/service/VirtualDeviceService.java @@ -0,0 +1,48 @@ +package com.qyft.ms.app.service; + +import cn.hutool.json.JSONObject; +import com.qyft.ms.system.model.bo.DeviceCommand; +import com.qyft.ms.system.service.device.DeviceCommandService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * 虚拟设备服务 + */ +@Service +@RequiredArgsConstructor +public class VirtualDeviceService { + private final DeviceCommandService deviceCommandService; + + public void completeCommandResponse(DeviceCommand cmdToDevice) { + new Thread(() -> { + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.putOnce("cmdId", cmdToDevice.getCmdId()); + jsonObject.putOnce("success", true); + + String code = cmdToDevice.getCmdCode(); + String action = cmdToDevice.getAction(); + String device = cmdToDevice.getDevice(); + if (code.contains("controlMotorCmd")) { + if (!action.contains("set")) {//非设置电机参数,也就是电机移动 + Thread.sleep(300); + } + } else if (code.contains("getInfoCmd")) { + if (device.contains("humidity")) { + if (action.contains("get")) {//获取温度 + JSONObject data = new JSONObject(); + data.putOnce("humidity", 26); + jsonObject.putOnce("data", data); + } + } + } + deviceCommandService.completeCommandResponse(jsonObject); + } catch (InterruptedException e) { + // 处理中断异常 + Thread.currentThread().interrupt(); + } + }).start(); + } + +} diff --git a/src/main/java/com/qyft/ms/system/service/device/DeviceCommandService.java b/src/main/java/com/qyft/ms/system/service/device/DeviceCommandService.java index 1d7db9c..f387cc2 100644 --- a/src/main/java/com/qyft/ms/system/service/device/DeviceCommandService.java +++ b/src/main/java/com/qyft/ms/system/service/device/DeviceCommandService.java @@ -1,6 +1,8 @@ package com.qyft.ms.system.service.device; import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.qyft.ms.app.core.event.VirtualDeviceCmdResponseEvent; import com.qyft.ms.app.device.status.DeviceStatus; import com.qyft.ms.system.common.constant.CommandStatus; import com.qyft.ms.system.common.device.command.CommandFuture; @@ -11,6 +13,7 @@ import com.qyft.ms.system.model.bo.DeviceCommand; import com.qyft.ms.system.service.WebSocketService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import java.util.concurrent.ConcurrentHashMap; @@ -20,13 +23,12 @@ import java.util.concurrent.ConcurrentMap; @Service @RequiredArgsConstructor public class DeviceCommandService { - private final ConcurrentMap commandFutureMap = new ConcurrentHashMap<>(); private final DeviceTcpClient deviceTcpClient; private final WebSocketService webSocketService; private final DeviceStatus deviceStatus; - + private final ApplicationEventPublisher publisher; public CommandFuture executeCommand(DeviceCommand cmdToDevice) { int cmdId = CyclicNumberGenerator.getInstance().generateNumber(); @@ -34,9 +36,16 @@ public class DeviceCommandService { CommandFuture cmdFuture = new CommandFuture(); commandFutureMap.put(cmdToDevice.getCmdId(), cmdFuture); cmdFuture.setStartSendTime(System.currentTimeMillis()); - if (!deviceTcpClient.sendToJSON(cmdToDevice)) { - commandFutureMap.remove(cmdToDevice.getCmdId()); - throw new RuntimeException("向设备发送指令失败"); + + if (deviceStatus.isVirtual()) { + log.info("模拟向设备发送TCP指令:{}", JSONUtil.toJsonStr(cmdToDevice)); + //模拟反馈 + publisher.publishEvent(new VirtualDeviceCmdResponseEvent(this, cmdToDevice)); + } else { + if (!deviceTcpClient.sendToJSON(cmdToDevice)) { + commandFutureMap.remove(cmdToDevice.getCmdId()); + throw new RuntimeException("向设备发送指令失败"); + } } cmdFuture.getResponseFuture().whenComplete((result, ex) -> {