diff --git a/src/main/java/com/iflytop/handacid/app/command/control/SolutionAddStartCommand.java b/src/main/java/com/iflytop/handacid/app/command/control/SolutionAddStartCommand.java new file mode 100644 index 0000000..369ab52 --- /dev/null +++ b/src/main/java/com/iflytop/handacid/app/command/control/SolutionAddStartCommand.java @@ -0,0 +1,100 @@ +package com.iflytop.handacid.app.command.control; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.iflytop.handacid.app.common.annotation.CommandMapping; +import com.iflytop.handacid.app.common.enums.ChannelCode; +import com.iflytop.handacid.app.common.enums.ChannelStateCode; +import com.iflytop.handacid.app.common.enums.SolutionAddMode; +import com.iflytop.handacid.app.common.utils.CommandUtil; +import com.iflytop.handacid.app.core.command.BaseCommandHandler; +import com.iflytop.handacid.app.core.command.CommandFuture; +import com.iflytop.handacid.app.core.command.DeviceCommand; +import com.iflytop.handacid.app.core.state.DeviceState; +import com.iflytop.handacid.app.model.dto.CommandDTO; +import com.iflytop.handacid.app.service.ChannelCtrlService; +import com.iflytop.handacid.app.service.DeviceCommandService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * 开始加液 + */ +@Slf4j +@Component +@RequiredArgsConstructor +@CommandMapping("solution_add_start") +public class SolutionAddStartCommand extends BaseCommandHandler { + private final DeviceCommandService deviceCommandService; + private final ChannelCtrlService channelCtrlService; + private final DeviceState deviceState; + + @Override + public CompletableFuture handle(CommandDTO commandDTO) { + JSONArray jsonArray = commandDTO.getJSONArrayParam("channelArray"); + List channelCodeList = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + String channelCodeStr = jsonObject.getStr("channelCode"); + if (channelCodeStr == null) { + throw new IllegalArgumentException("参数 channelCode 不能为空"); + } + ChannelCode channelCode = ChannelCode.valueOf(channelCodeStr); + channelCodeList.add(channelCode); + Double volume = jsonObject.getDouble("volume"); + if (volume == null) { + throw new IllegalArgumentException("参数 volume 不能为空"); + } + } + SolutionAddMode mode = commandDTO.getEnumParam("mode", SolutionAddMode.class); + Integer delay = commandDTO.getIntegerParam("delay"); + if (mode == null) { + throw new IllegalArgumentException("参数 mode 不能为空"); + } + return runAsync(() -> { + try { + for (ChannelCode channelCode : channelCodeList) { + deviceState.getChannelStateMap().get(channelCode).setStateCode(ChannelStateCode.ADD); + } + if (SolutionAddMode.AUTO.equals(mode)) {//自动模式 + while (!deviceState.isSolutionAddStop()) { + List commandFutureList = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + String channelCodeStr = jsonObject.getStr("channelCode"); + ChannelCode channelCode = ChannelCode.valueOf(channelCodeStr); + + Double volume = jsonObject.getDouble("volume"); + DeviceCommand deviceCommand = channelCtrlService.getPumpMoveByCommandByChannel(channelCode, volume); + commandFutureList.add(deviceCommandService.sendCommand(deviceCommand)); + } + CommandUtil.wait(commandFutureList); + Thread.sleep(delay * 1000L); + } + } else if (SolutionAddMode.CLICK.equals(mode)) {//点动模式 + List commandFutureList = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + String channelCodeStr = jsonObject.getStr("channelCode"); + ChannelCode channelCode = ChannelCode.valueOf(channelCodeStr); + deviceState.getChannelStateMap().get(channelCode).setStateCode(ChannelStateCode.ADD); + Double volume = jsonObject.getDouble("volume"); + DeviceCommand deviceCommand = channelCtrlService.getPumpMoveByCommandByChannel(channelCode, volume); + commandFutureList.add(deviceCommandService.sendCommand(deviceCommand)); + } + CommandUtil.wait(commandFutureList); + } + } finally { + for (ChannelCode channelCode : channelCodeList) { + deviceState.getChannelStateMap().get(channelCode).setStateCode(ChannelStateCode.IDLE); + } + } + }); + } +} + diff --git a/src/main/java/com/iflytop/handacid/app/command/control/SolutionAddStopCommand.java b/src/main/java/com/iflytop/handacid/app/command/control/SolutionAddStopCommand.java new file mode 100644 index 0000000..2490e2f --- /dev/null +++ b/src/main/java/com/iflytop/handacid/app/command/control/SolutionAddStopCommand.java @@ -0,0 +1,55 @@ +package com.iflytop.handacid.app.command.control; + +import com.iflytop.handacid.app.common.annotation.CommandMapping; +import com.iflytop.handacid.app.common.enums.ChannelStateCode; +import com.iflytop.handacid.app.common.utils.CommandUtil; +import com.iflytop.handacid.app.core.command.BaseCommandHandler; +import com.iflytop.handacid.app.core.command.CommandFuture; +import com.iflytop.handacid.app.core.command.DeviceCommand; +import com.iflytop.handacid.app.core.state.ChannelState; +import com.iflytop.handacid.app.core.state.DeviceState; +import com.iflytop.handacid.app.model.dto.CommandDTO; +import com.iflytop.handacid.app.service.ChannelCtrlService; +import com.iflytop.handacid.app.service.DeviceCommandService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * 停止加液 + */ +@Slf4j +@Component +@RequiredArgsConstructor +@CommandMapping("solution_add_stop") +public class SolutionAddStopCommand extends BaseCommandHandler { + private final DeviceCommandService deviceCommandService; + private final ChannelCtrlService channelCtrlService; + private final DeviceState deviceState; + + @Override + public CompletableFuture handle(CommandDTO commandDTO) { + + return runAsync(() -> { + List channelCodeList = deviceState.filterChannelStatesByState(ChannelStateCode.ADD); + deviceState.setSolutionAddStop(true); + try { + List commandFutureList = new ArrayList<>(); + for (ChannelState channelState : channelCodeList) { + DeviceCommand deviceCommand = channelCtrlService.getPumpStopCommandByChannel(channelState.getChannelCode()); + commandFutureList.add(deviceCommandService.sendCommand(deviceCommand)); + } + CommandUtil.wait(commandFutureList); + } finally { + for (ChannelState channelCode : channelCodeList) { + channelCode.setStateCode(ChannelStateCode.IDLE); + } + } + }); + } +} + diff --git a/src/main/java/com/iflytop/handacid/app/command/control/StopAllMotorCommand.java b/src/main/java/com/iflytop/handacid/app/command/control/StopAllMotorCommand.java deleted file mode 100644 index 57598fd..0000000 --- a/src/main/java/com/iflytop/handacid/app/command/control/StopAllMotorCommand.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.iflytop.handacid.app.command.control; - -import com.iflytop.handacid.app.common.annotation.CommandMapping; -import com.iflytop.handacid.app.core.command.BaseCommandHandler; -import com.iflytop.handacid.app.model.dto.CommandDTO; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.concurrent.CompletableFuture; - -/** - * 停止所有电机 - */ -@Slf4j -@Component -@RequiredArgsConstructor -@CommandMapping("stop_all_motor") -public class StopAllMotorCommand extends BaseCommandHandler { - - @Override - public CompletableFuture handle(CommandDTO commandDTO) { - - return runAsync(() -> { - }); - } -} - diff --git a/src/main/java/com/iflytop/handacid/app/common/enums/SolutionAddMode.java b/src/main/java/com/iflytop/handacid/app/common/enums/SolutionAddMode.java new file mode 100644 index 0000000..9c649ce --- /dev/null +++ b/src/main/java/com/iflytop/handacid/app/common/enums/SolutionAddMode.java @@ -0,0 +1,5 @@ +package com.iflytop.handacid.app.common.enums; + +public enum SolutionAddMode { + AUTO, CLICK +} diff --git a/src/main/java/com/iflytop/handacid/app/common/utils/CommandUtil.java b/src/main/java/com/iflytop/handacid/app/common/utils/CommandUtil.java index 4dc9e8d..f50e15d 100644 --- a/src/main/java/com/iflytop/handacid/app/common/utils/CommandUtil.java +++ b/src/main/java/com/iflytop/handacid/app/common/utils/CommandUtil.java @@ -4,11 +4,16 @@ package com.iflytop.handacid.app.common.utils; import com.iflytop.handacid.app.core.command.CommandFuture; import java.util.Arrays; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class CommandUtil { + public static void wait(List futures) throws Exception { + wait(futures.toArray(new CommandFuture[0])); + } + public static void wait(CommandFuture... futures) throws Exception { wait(120L, futures); } diff --git a/src/main/java/com/iflytop/handacid/app/core/state/DeviceState.java b/src/main/java/com/iflytop/handacid/app/core/state/DeviceState.java index 113633d..5b9bf7d 100644 --- a/src/main/java/com/iflytop/handacid/app/core/state/DeviceState.java +++ b/src/main/java/com/iflytop/handacid/app/core/state/DeviceState.java @@ -2,6 +2,7 @@ package com.iflytop.handacid.app.core.state; import cn.hutool.json.JSONObject; import com.iflytop.handacid.app.common.enums.ChannelCode; +import com.iflytop.handacid.app.common.enums.ChannelStateCode; import com.iflytop.handacid.common.model.entity.User; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -9,7 +10,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Schema(description = "设备当前状态") @Data @@ -18,6 +21,9 @@ public class DeviceState { @Schema(description = "通道状态") private final Map channelStateMap = new HashMap<>(); + @Schema(description = "是否停止加液") + private volatile boolean solutionAddStop = false; + @Schema(description = "虚拟模式,true为虚拟") private volatile boolean virtual = false; @@ -35,4 +41,13 @@ public class DeviceState { json.putOnce("currentUser", currentUser); return json; } + + /** + * 根据状态码筛选出子 + */ + public List filterChannelStatesByState(ChannelStateCode stateCode) { + return channelStateMap.values().stream() + .filter(cs -> cs.getStateCode() == stateCode) + .collect(Collectors.toList()); + } } \ No newline at end of file diff --git a/src/main/java/com/iflytop/handacid/app/model/dto/CommandDTO.java b/src/main/java/com/iflytop/handacid/app/model/dto/CommandDTO.java index f19e632..7d4e3e7 100644 --- a/src/main/java/com/iflytop/handacid/app/model/dto/CommandDTO.java +++ b/src/main/java/com/iflytop/handacid/app/model/dto/CommandDTO.java @@ -66,6 +66,29 @@ public class CommandDTO { return new JSONArray(value); } + /** + * 获取枚举类型参数,null 或空字符串时返回 null, + * 找不到枚举值时也返回 null(或者你也可以改成抛异常) + * + * @param key 参数名 + * @param enumClass 枚举 Class 对象 + * @param 枚举类型 + * @return 转换后的枚举实例,或 null + */ + public > E getEnumParam(String key, Class enumClass) { + String value = getStringParam(key); + if (value == null || value.isEmpty()) { + return null; + } + try { + // 如果枚举名称和参数不完全一致,可先做大小写转换 + return Enum.valueOf(enumClass, value.trim()); + } catch (IllegalArgumentException e) { + // 找不到对应的枚举时,返回 null 或者你也可以抛出自定义异常 + return null; + } + } + @Override public String toString() { return JSONUtil.toJsonStr(this); diff --git a/src/main/java/com/iflytop/handacid/app/service/ChannelCtrlService.java b/src/main/java/com/iflytop/handacid/app/service/ChannelCtrlService.java new file mode 100644 index 0000000..ca25f40 --- /dev/null +++ b/src/main/java/com/iflytop/handacid/app/service/ChannelCtrlService.java @@ -0,0 +1,65 @@ +package com.iflytop.handacid.app.service; + +import com.iflytop.handacid.app.common.enums.ChannelCode; +import com.iflytop.handacid.app.common.enums.ChannelStateCode; +import com.iflytop.handacid.app.core.command.DeviceCommand; +import com.iflytop.handacid.app.core.command.DeviceCommandGenerator; +import com.iflytop.handacid.app.core.state.DeviceState; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 通道控制 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class ChannelCtrlService { + private final DeviceCommandService deviceCommandService; + private final DeviceState deviceState; + + + /** + * 根据通道code获取泵相对移动指令 + */ + public DeviceCommand getPumpMoveByCommandByChannel(ChannelCode channelCode, Double position) { + return switch (channelCode) { + case CHANNEL_1 -> DeviceCommandGenerator.pump1MoveBy(position); + case CHANNEL_2 -> DeviceCommandGenerator.pump2MoveBy(position); + case CHANNEL_3 -> DeviceCommandGenerator.pump3MoveBy(position); + case CHANNEL_4 -> DeviceCommandGenerator.pump4MoveBy(position); + }; + } + + /** + * 根据通道code获取停止泵指令 + */ + public DeviceCommand getPumpStopCommandByChannel(ChannelCode channelCode) { + return switch (channelCode) { + case CHANNEL_1 -> DeviceCommandGenerator.pump1Stop(); + case CHANNEL_2 -> DeviceCommandGenerator.pump2Stop(); + case CHANNEL_3 -> DeviceCommandGenerator.pump3Stop(); + case CHANNEL_4 -> DeviceCommandGenerator.pump4Stop(); + }; + } + + /** + * 加液 + * + * @param channelCode 通道code + * @param volume 加液量 + */ + public void solutionAddStart(ChannelCode channelCode, Double volume) { + + } + + /** + * 停止加液 + * @param channelCode 通道code + */ + public void solutionAddStop(ChannelCode channelCode) { + deviceState.getChannelStateMap().get(channelCode).setStateCode(ChannelStateCode.IDLE); + + } +}