diff --git a/src/main/java/com/iflytop/sgs/SeparateGoldServiceApplication.java b/src/main/java/com/iflytop/sgs/SeparateGoldServiceApplication.java index 0adc945..daedf45 100644 --- a/src/main/java/com/iflytop/sgs/SeparateGoldServiceApplication.java +++ b/src/main/java/com/iflytop/sgs/SeparateGoldServiceApplication.java @@ -2,14 +2,28 @@ package com.iflytop.sgs; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; @SpringBootApplication -@EnableAspectJAutoProxy(proxyTargetClass = true) public class SeparateGoldServiceApplication { public static void main(String[] args) { - SpringApplication.run(SeparateGoldServiceApplication.class, args); + SpringApplication app = new SpringApplication(SeparateGoldServiceApplication.class); + app.addInitializers(ctx -> { + try { + Thread.sleep(0); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + + ConfigurableApplicationContext ctx = app.run(args); + ConfigurableEnvironment env = ctx.getEnvironment(); + String port = env.getProperty("local.server.port", env.getProperty("server.port", "8080")); + System.out.println("应用已启动"); + System.out.println("访问地址 → http://localhost:" + port + "/"); + System.out.println("文档地址 → http://localhost:" + port + "/doc.html"); } } diff --git a/src/main/java/com/iflytop/sgs/app/cmd/control/LiquidAddCommand.java b/src/main/java/com/iflytop/sgs/app/cmd/control/LiquidAddCommand.java index 93d0093..48d0ca7 100644 --- a/src/main/java/com/iflytop/sgs/app/cmd/control/LiquidAddCommand.java +++ b/src/main/java/com/iflytop/sgs/app/cmd/control/LiquidAddCommand.java @@ -101,7 +101,7 @@ public class LiquidAddCommand extends BaseCommandHandler { double scale = Double.parseDouble(systemConfigService.getSystemConfigValueByCode(valveStateCode.getSystemConfigCode()));//根据溶液获取转换比 double position = volume * scale * 8 + preFillDistance;//加液泵的转数 solutionModuleService.liquidValveSwitch(cmdDTO.getCommandId(), cmdDTO.getCommand(), valveStateCode);//电磁阀对应通道打开 - deviceStateService.getDeviceState().getSolutionModule().getValveState().setState(valveStateCode);//设置阀门状态 + deviceStateService.getDeviceState().getSolutionModule().setValveState(valveStateCode);//设置阀门状态 for (int i = 0; i < jsonArray.size(); i++) { int column = jsonArray.getInt(i); if (column > 0 && column < 6) { diff --git a/src/main/java/com/iflytop/sgs/app/controller/TrayController.java b/src/main/java/com/iflytop/sgs/app/controller/TrayController.java index c7f7463..cd51795 100644 --- a/src/main/java/com/iflytop/sgs/app/controller/TrayController.java +++ b/src/main/java/com/iflytop/sgs/app/controller/TrayController.java @@ -32,7 +32,7 @@ public class TrayController { @Operation(summary = "拿走托盘") @PostMapping("/out") - public Result trayOut() { + public Result trayOut(){ trayService.trayOut(); return Result.success(); } diff --git a/src/main/java/com/iflytop/sgs/app/core/CraftsContext.java b/src/main/java/com/iflytop/sgs/app/core/CraftsContext.java index 1e26ab7..7e6fa52 100644 --- a/src/main/java/com/iflytop/sgs/app/core/CraftsContext.java +++ b/src/main/java/com/iflytop/sgs/app/core/CraftsContext.java @@ -2,11 +2,14 @@ package com.iflytop.sgs.app.core; import cn.hutool.json.JSONUtil; import com.iflytop.sgs.app.model.bo.CraftsStep; +import com.iflytop.sgs.app.model.bo.status.crafts.CraftsState; import com.iflytop.sgs.app.model.entity.Crafts; import com.iflytop.sgs.app.model.entity.Ores; import com.iflytop.sgs.app.service.crafts.CraftsStepService; +import com.iflytop.sgs.app.service.device.DeviceStateService; import com.iflytop.sgs.app.ws.server.WebSocketSender; import com.iflytop.sgs.common.constant.WebSocketMessageType; +import com.iflytop.sgs.common.enums.HeatModuleCode; import com.iflytop.sgs.common.enums.automaton.CraftEvents; import com.iflytop.sgs.common.enums.automaton.CraftStates; import lombok.Getter; @@ -26,36 +29,47 @@ import java.util.Map; @Slf4j @Getter public class CraftsContext implements Runnable { - private final String heatId; + private final HeatModuleCode heatModuleCode; private final Ores ores; private final Crafts craft; private final List craftsStepList; private final StateMachine sm; private final WebSocketSender webSocketService; private final CraftsStepService craftsStepService; + private final DeviceStateService deviceStateService; private int currentIndex = 0; /** * 构造方法,初始化上下文并启动状态机至 READY */ - public CraftsContext(String heatId, Ores ores, + public CraftsContext(HeatModuleCode heatModuleCode, Ores ores, Crafts craft, StateMachineFactory factory, WebSocketSender webSocketService, - CraftsStepService craftsStepService) { - this.heatId = heatId; + CraftsStepService craftsStepService, + DeviceStateService deviceStateService) { + this.heatModuleCode = heatModuleCode; this.ores = ores; this.craft = craft; this.craftsStepList = JSONUtil.parseArray(craft.getSteps()).toList(CraftsStep.class); this.webSocketService = webSocketService; this.craftsStepService = craftsStepService; + this.deviceStateService = deviceStateService; + + this.sm = factory.getStateMachine(heatModuleCode.toString()); + + CraftsState craftsState = new CraftsState(); + craftsState.setState(sm.getState().getId()); + craftsState.setOres(ores); + craftsState.setCraft(craft); + craftsState.setCurrentIndex(currentIndex); + deviceStateService.getDeviceState().getTrayByHeatModuleCode(heatModuleCode).setCrafts(craftsState); - this.sm = factory.getStateMachine(heatId); sm.addStateListener(new StateMachineListenerAdapter<>() { @Override public void stateEntered(State state) { Map dataMap = new HashMap<>(); - dataMap.put("heatId", heatId); + dataMap.put("heatId", heatModuleCode.toString()); dataMap.put("state", state.getId()); dataMap.put("index", currentIndex); webSocketService.push(WebSocketMessageType.CRAFTS_STATE, dataMap); @@ -98,7 +112,7 @@ public class CraftsContext implements Runnable { } } catch (Exception e) { log.error("工艺执行失败", e); - webSocketService.pushCraftsDebug(CraftsDebugGenerator.generateJson(heatId, "工艺执行失败", e.getMessage())); + webSocketService.pushCraftsDebug(CraftsDebugGenerator.generateJson(heatModuleCode.toString(), "工艺执行失败", e.getMessage())); Message stopMsg = MessageBuilder.withPayload(CraftEvents.ERROR_OCCUR).build(); Mono.from(sm.sendEvent(Mono.just(stopMsg))).block(); } @@ -113,10 +127,10 @@ public class CraftsContext implements Runnable { */ private boolean executeStep(CraftsStep step) throws Exception { Map startData = new HashMap<>(); - startData.put("heatId", heatId); + startData.put("heatId", heatModuleCode.toString()); startData.put("currentStep", step.getMethod()); webSocketService.push(WebSocketMessageType.CRAFTS_STEP, startData); - return craftsStepService.executeStep(heatId, step); + return craftsStepService.executeStep(heatModuleCode.toString(), step); } /** diff --git a/src/main/java/com/iflytop/sgs/app/core/aspect/DeviceStateChangeAspect.java b/src/main/java/com/iflytop/sgs/app/core/aspect/DeviceStateChangeAspect.java index 036f137..aaab584 100644 --- a/src/main/java/com/iflytop/sgs/app/core/aspect/DeviceStateChangeAspect.java +++ b/src/main/java/com/iflytop/sgs/app/core/aspect/DeviceStateChangeAspect.java @@ -8,12 +8,8 @@ import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - @Slf4j @Aspect @Component @@ -22,41 +18,20 @@ public class DeviceStateChangeAspect { private final WebSocketSender webSocketService; private final DeviceStateService deviceStateService; - private final Lock lock = new ReentrantLock(); - private Object beforeValue; - - - @Before("execution(* com.iflytop.sgs.app.model.bo.status..set*(..))") - public void beforeSetMethod(JoinPoint joinPoint) { - lock.lock(); - try { - System.out.println(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); - Object[] methodArgs = joinPoint.getArgs(); - if (methodArgs != null && methodArgs.length > 0) { - beforeValue = methodArgs[0]; - } - } catch (Exception e) { - log.error("处理状态变更前的值失败", e); - } - } - - @After("execution(* com.iflytop.sgs.app.model.bo.status..set*(..))") + @After("execution(* com.iflytop.sgs.app.model.bo.status.device.*.set*(..))") public void afterSetMethod(JoinPoint joinPoint) { try { String className = joinPoint.getSignature().getDeclaringType().getName(); // 获取类名 String methodName = joinPoint.getSignature().getName(); Object[] methodArgs = joinPoint.getArgs(); - System.out.println(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); if (methodArgs != null && methodArgs.length > 0) { // 保存修改后的值 Object afterValue = methodArgs[0]; - log.info("设备状态发生改变,类型{}.{} ,from {} to {}", className, methodName, beforeValue, afterValue); + log.info("设备状态发生改变,类型{}.{}({})", className, methodName, afterValue); webSocketService.push(WebSocketMessageType.STATUS, deviceStateService.getDeviceState()); } } catch (Exception e) { log.error("处理状态变更后的值失败", e); - } finally { - lock.unlock(); } } } diff --git a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/DeviceState.java b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/DeviceState.java index 5baf9d5..0872c80 100644 --- a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/DeviceState.java +++ b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/DeviceState.java @@ -1,27 +1,35 @@ package com.iflytop.sgs.app.model.bo.status.device; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.iflytop.sgs.app.model.entity.Tasks; import com.iflytop.sgs.app.model.entity.User; import com.iflytop.sgs.common.enums.HeatModuleCode; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Schema(description = "当前设备") @Data +@Component +@Scope("prototype") +@RequiredArgsConstructor +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) public class DeviceState { @Schema(description = "门状态") - private final DoorModuleState doorModule = new DoorModuleState(); + private final DoorModuleState doorModule; @Schema(description = "转运机械臂状态") - private final TransferModuleState transferModule = new TransferModuleState(); + private final TransferModuleState transferModule; @Schema(description = "加液模块属性") - private final SolutionModuleState solutionModule = new SolutionModuleState(); + private final SolutionModuleState solutionModule; @Schema(description = "加热模块属性") - private final List heatModule = new ArrayList<>(); + private List heatModule = new ArrayList<>(); @Schema(description = "托盘") - private final List trays = new ArrayList<>(); + private List trays = new ArrayList<>(); @Schema(description = "虚拟模式,true为虚拟") private boolean virtual = false; @Schema(description = "初始化状态,true初始化完毕") @@ -70,6 +78,7 @@ public class DeviceState { } return null; } + public synchronized TrayState getTrayState(String trayUUID) { for (TrayState t : trays) { if (t.getUuid().equals(trayUUID)) { @@ -79,4 +88,22 @@ public class DeviceState { return null; } + /** + * 获取一个空闲的加热模块 + */ + public synchronized HeatModuleState getFirstIdleHeatModule() { + for (HeatModuleState h : heatModule) { + if (!h.isEnable()) { + continue; + } + for (TrayState t : trays) { + if (h.getModuleCode().equals(t.getHeatModuleCode())) { + break; + } + } + return h; + } + return null; + } + } diff --git a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/DoorModuleState.java b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/DoorModuleState.java index d16e215..10b6caa 100644 --- a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/DoorModuleState.java +++ b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/DoorModuleState.java @@ -1,10 +1,16 @@ package com.iflytop.sgs.app.model.bo.status.device; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; @Schema(description = "门") @Data +@Component +@Scope("prototype") +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) public class DoorModuleState { @Schema(description = "是否开门,true为开启状态,false为关闭状态") private boolean open = false; diff --git a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/HeatModuleState.java b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/HeatModuleState.java index 6e180cf..90e4ecc 100644 --- a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/HeatModuleState.java +++ b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/HeatModuleState.java @@ -1,12 +1,20 @@ package com.iflytop.sgs.app.model.bo.status.device; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.iflytop.sgs.common.enums.HeatModuleCode; import com.iflytop.sgs.common.enums.HeatingType; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; @Schema(description = "加热模块") @Data +@Component +@Scope("prototype") +@RequiredArgsConstructor +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) public class HeatModuleState { @Schema(description = "加热模块code") private HeatModuleCode moduleCode; diff --git a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/SolutionContainerState.java b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/SolutionContainerState.java index ceaa771..43dd2b0 100644 --- a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/SolutionContainerState.java +++ b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/SolutionContainerState.java @@ -1,12 +1,20 @@ package com.iflytop.sgs.app.model.bo.status.device; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.iflytop.sgs.common.enums.ContainerCode; import com.iflytop.sgs.common.enums.ContainerType; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; @Schema(description = "溶液容器") @Data +@Component +@Scope("prototype") +@RequiredArgsConstructor +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) public class SolutionContainerState { @Schema(description = "容器数据id") private Long id; diff --git a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/SolutionModuleState.java b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/SolutionModuleState.java index f537a23..75ef181 100644 --- a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/SolutionModuleState.java +++ b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/SolutionModuleState.java @@ -1,14 +1,23 @@ package com.iflytop.sgs.app.model.bo.status.device; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.iflytop.sgs.common.enums.ContainerCode; +import com.iflytop.sgs.common.enums.ValveStateCode; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Schema(description = "加液模块") @Data +@Component +@Scope("prototype") +@RequiredArgsConstructor +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) public class SolutionModuleState { @Schema(description = "是否空闲,true为空闲,false为占用") private boolean idle = true; @@ -22,8 +31,8 @@ public class SolutionModuleState { @Schema(description = "是否正在加液,true正在加液,false未运行") private boolean pumping = false; - @Schema(description = "电磁阀状态") - private ValveState valveState; + @Schema(description = "当前电磁阀通道") + private ValveStateCode valveState; /* * 根据容器code获取容器状态 diff --git a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/TransferModuleState.java b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/TransferModuleState.java index a2a7d06..75be8c5 100644 --- a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/TransferModuleState.java +++ b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/TransferModuleState.java @@ -1,10 +1,18 @@ package com.iflytop.sgs.app.model.bo.status.device; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; @Schema(description = "转运模块") @Data +@Component +@Scope("prototype") +@RequiredArgsConstructor +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) public class TransferModuleState { @Schema(description = "是否空闲,true为空闲,false为占用") private boolean idle = true; diff --git a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/TrayState.java b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/TrayState.java index 8ca4754..bb4ef11 100644 --- a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/TrayState.java +++ b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/TrayState.java @@ -1,14 +1,23 @@ package com.iflytop.sgs.app.model.bo.status.device; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.iflytop.sgs.app.model.bo.status.crafts.CraftsState; import com.iflytop.sgs.common.enums.HeatModuleCode; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.annotation.PostConstruct; import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; import java.util.UUID; @Schema(description = "托盘") @Data +@Component +@Scope("prototype") +@RequiredArgsConstructor +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) public class TrayState { @Schema(description = "托盘唯一id") private String uuid = UUID.randomUUID().toString(); @@ -31,11 +40,13 @@ public class TrayState { @Schema(description = "当前托盘的工艺") private CraftsState crafts = null; - public TrayState() { + @PostConstruct + private void init() { for (int i = 0; i < tubes.length; i++) { TubeState tubeState = new TubeState(); tubeState.setColumnNum(i + 1); tubes[i] = tubeState; } } + } diff --git a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/ValveState.java b/src/main/java/com/iflytop/sgs/app/model/bo/status/device/ValveState.java deleted file mode 100644 index 3e4e7ea..0000000 --- a/src/main/java/com/iflytop/sgs/app/model/bo/status/device/ValveState.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.iflytop.sgs.app.model.bo.status.device; - -import com.iflytop.sgs.common.enums.ValveStateCode; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "电磁阀状态") -@Data -public class ValveState { - - @Schema(description = "当前电磁阀通道") - private ValveStateCode state; - -} diff --git a/src/main/java/com/iflytop/sgs/app/model/dto/SetCraftsDTO.java b/src/main/java/com/iflytop/sgs/app/model/dto/SetCraftsDTO.java index 0fc5f5d..311bbe9 100644 --- a/src/main/java/com/iflytop/sgs/app/model/dto/SetCraftsDTO.java +++ b/src/main/java/com/iflytop/sgs/app/model/dto/SetCraftsDTO.java @@ -13,7 +13,6 @@ public class SetCraftsDTO { @Schema(description = "工艺id") private Long craftId; - @NotNull @Schema(description = "加热区id") private String heatId; } diff --git a/src/main/java/com/iflytop/sgs/app/service/api/CraftsService.java b/src/main/java/com/iflytop/sgs/app/service/api/CraftsService.java index 0546c73..05fff1d 100644 --- a/src/main/java/com/iflytop/sgs/app/service/api/CraftsService.java +++ b/src/main/java/com/iflytop/sgs/app/service/api/CraftsService.java @@ -4,12 +4,16 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.iflytop.sgs.app.core.CraftsContext; import com.iflytop.sgs.app.mapper.CraftsMapper; +import com.iflytop.sgs.app.model.bo.status.crafts.CraftsState; +import com.iflytop.sgs.app.model.bo.status.device.HeatModuleState; import com.iflytop.sgs.app.model.entity.Crafts; import com.iflytop.sgs.app.model.entity.Ores; import com.iflytop.sgs.app.model.vo.CraftStatusVO; import com.iflytop.sgs.app.model.vo.SetCraftsVO; import com.iflytop.sgs.app.service.crafts.CraftsStepService; +import com.iflytop.sgs.app.service.device.DeviceStateService; import com.iflytop.sgs.app.ws.server.WebSocketSender; +import com.iflytop.sgs.common.enums.HeatModuleCode; import com.iflytop.sgs.common.enums.automaton.CraftEvents; import com.iflytop.sgs.common.enums.automaton.CraftStates; import com.iflytop.sgs.common.exception.AppException; @@ -33,6 +37,7 @@ import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class CraftsService extends ServiceImpl { + private final DeviceStateService deviceStateService; private final StateMachineFactory stateMachineFactory; private final WebSocketSender webSocketService; private final CraftsStepService craftsStepService; @@ -50,6 +55,19 @@ public class CraftsService extends ServiceImpl { * 配置工艺 */ public synchronized SetCraftsVO setCraft(Long craftId, String heatId) { + HeatModuleCode heatModuleCode; + if(heatId == null){ + //获取一个空加热模块 + HeatModuleState idleHeatModule = deviceStateService.getDeviceState().getFirstIdleHeatModule(); + if (idleHeatModule == null) { + throw new AppException(ResultCode.CRAFT_IDLE_HEAT_MODULE_NOT_FOUND); + } + heatModuleCode = idleHeatModule.getModuleCode(); + heatId = heatModuleCode.toString(); + + }else{ + heatModuleCode = HeatModuleCode.valueOf(heatId); + } // 校验已有上下文状态,仅允许在 READY、STOPPED 或 FINISHED 状态下重置 CraftsContext existing = contextMap.get(heatId); if (existing != null) { @@ -62,14 +80,16 @@ public class CraftsService extends ServiceImpl { Crafts craft = this.getById(craftId); Ores ores = oresService.getById(craft.getOresId()); CraftsContext ctx = new CraftsContext( - heatId, + heatModuleCode, ores, craft, stateMachineFactory, webSocketService, - craftsStepService + craftsStepService, + deviceStateService ); contextMap.put(heatId, ctx); + SetCraftsVO setCraftsVO = new SetCraftsVO(); setCraftsVO.setHeatId(heatId); setCraftsVO.setCraftsName(craft.getName()); diff --git a/src/main/java/com/iflytop/sgs/app/service/api/TrayService.java b/src/main/java/com/iflytop/sgs/app/service/api/TrayService.java index 183898c..a804559 100644 --- a/src/main/java/com/iflytop/sgs/app/service/api/TrayService.java +++ b/src/main/java/com/iflytop/sgs/app/service/api/TrayService.java @@ -4,6 +4,8 @@ import com.iflytop.sgs.app.model.bo.status.device.TrayState; import com.iflytop.sgs.app.model.vo.SetTrayTubeVO; import com.iflytop.sgs.app.service.device.DeviceStateService; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.stereotype.Service; import java.util.List; @@ -15,12 +17,13 @@ import java.util.List; @RequiredArgsConstructor public class TrayService { private final DeviceStateService deviceStateService; + private final ObjectProvider trayStateProvider; /** * 放入了新托盘 */ public synchronized TrayState trayIn() { - TrayState trayState = new TrayState(); + TrayState trayState = trayStateProvider.getObject(); trayState.setInFeedArea(true); deviceStateService.getDeviceState().getTrays().add(trayState); deviceStateService.getDeviceState().getSolutionModule().setFeedAreaTrayStatus(true); @@ -30,9 +33,9 @@ public class TrayService { /** * 拿走了托盘 */ - public synchronized void trayOut() { + public synchronized void trayOut(){ List trayList = deviceStateService.getDeviceState().getTrays(); - trayList.removeIf(TrayState::isInSolutionPositon); + trayList.removeIf(TrayState::isInFeedArea); deviceStateService.getDeviceState().getSolutionModule().setFeedAreaTrayStatus(false); } diff --git a/src/main/java/com/iflytop/sgs/app/service/crafts/CraftsStepService.java b/src/main/java/com/iflytop/sgs/app/service/crafts/CraftsStepService.java index 8dbf91f..84a3a47 100644 --- a/src/main/java/com/iflytop/sgs/app/service/crafts/CraftsStepService.java +++ b/src/main/java/com/iflytop/sgs/app/service/crafts/CraftsStepService.java @@ -30,61 +30,12 @@ public class CraftsStepService { String method = step.getMethod(); JSONObject params = step.getParams(); - //设备包含分步运行模式以及自动调度模式。分步运行模式共分为5步;自动调度模式则是根据五个步骤按照时间间隔,以及优先级顺序进行自动执行。 - //分步模式: - //(人员将准备好的样品手动放入试管中,再放置到设备的上料工位后:) + //加液(弱、强、水、量) + //抽取 + //加热(温度、时间) + //退火(温度、时间) - //第一步: - //夹具将托盘取走,转移至自动化加酸工位进行逐排加酸,加酸后放置再相应的石墨炉中进行加热,加热温度约100℃。 - //第二步: - //将托盘从石墨炉中取出进行抽酸,抽酸后逐排添加第二种酸液,然后再放回石墨炉中进行加热, 加热温度约100℃。 - //第三步:将托盘从石墨炉中取出进行抽酸,抽酸后逐排添加满蒸馏水,再将水抽走,重复清洗两遍,将托盘放置回石墨炉中进行烘干水分,温度升高至150℃。烘干15min。 - //第四步:烘干后将托盘转移至退火工位,在400℃下退火5min。 - //第五步:将托盘取走放置在下料工位。 - //具体操作流程:(单批样品操作流程) - //1 人员上料、设定及开始 : - // 人员手动将样品放至上料工位,设定分金时间,记录分金编号,按开始键开始分金。 - - //2 执行分步程序第一步:加酸 - //如果三个电炉当中有空闲电炉,并且空闲电炉的温度在120摄氏度以下,则具备自动流程开始条件。自动执行分步程序第一步 - - //3 等待一段时间进行反应。(默认时间20min,可在开始之前单独设置。) - - //4 执行分步程序第二步:换酸 - // 到时间后,系统对此炉样品自动执行分步程序第二步。 - - //5 再次等待一段时间进行反应。(默认时间19min,可在开始之前单独设置。) - - //6 执行分步程序第三步:清洗及烘干 - //到时间后,系统对此炉样品自动执行分步程序第三步。 - - //7 再次等待一段时间进行反应。(默认时间20min,可在开始之前单独设置。) - - //8 执行分步程序第四步:退火 - //到时间后,系统对此炉样品自动执行分步程序第四步。 - - //9 再次等待一段时间进行反应。(默认时间5min,可在开始之前单独设置。) - - //10 执行分步程序第五步:下料 - //到时间后,系统对此炉样品自动执行分步程序第五步,流程结束。 - //注:下料时需判断下料工位传感器,无托盘,否则发出报错提示。 - //(每批样品的工艺流程均为上述10个步骤,其中有五个自动操作步骤。操作步骤耗时一般在几分钟之内。加热时间稍微延长对检测结果没有影响(夹具忙碌,没有立即执行对检测检测结果没有影响)。 - - //多批样品自动调度规则: - //由于设备具备三个电炉 ,可交错处理三批样品。每批样品均是同样的流程,但上料的时间不固定(也就是每批样品 被人员准备好并拿到上料工位 的时间不固定)。以下为处理原则: - //(1)每批样品上料的时间不固定,只要上/下料工位上没有样品,并且有电炉空余,且电炉温度小于120度,均可上料开始流程。 - //(3)工艺开始时,若三个电炉均无样品,优先将样品放置在左边的电炉;电炉A中有样品时,则将样品放置在电炉B中;若电炉AB均有样品,则放置在电炉C中。 - //(4)样品处理的时间均可延后,没有必须立即执行的步骤。当有某一批样品到时间需要执行某一步时,若此时机械臂正在处理其他样品,则当前任务挂起,等待夹具处理完上一个任务,再进行处理即可。 - //如果有多个任务先后到达处理时间需要进行处理,此时有任务正在执行。则需要将这些任务按照时间顺序都挂起,等待任务执行完毕之后再依次执行,在执行过程中如果有新的任务生成,则继续依次挂起,逐个操作。 - - - //需求功能统计: - //1 开始自动调度模式之前,开始界面显示四个等待时间(上述第3,5,7,9步),按照默认数值进行显示,可以支持修改。 - //2 可单独中断某一批次样品,中断后人员把托盘取走,不继续执行流程。需要回原位的人员手动将机械臂等回原位。以便出现问题时可以再次重新执行流程。 - //3 可以选择直接从五步中的某一步进行执行。也就是从中间开始执行,不从第一步开始执行。也可以设置n分钟后开始,不立即执行。 - //4 系统故障重启后可以恢复断电前状态。继续自动流程。 - //5 遇到有电炉损坏,不具备上料、开始自动流程条件时。可以手动把这条线关掉,执行第一步时不会选择向这条线进行放置样品。 return switch (method) { default -> true; diff --git a/src/main/java/com/iflytop/sgs/app/service/device/DeviceInitService.java b/src/main/java/com/iflytop/sgs/app/service/device/DeviceInitService.java index 34e2233..4138907 100644 --- a/src/main/java/com/iflytop/sgs/app/service/device/DeviceInitService.java +++ b/src/main/java/com/iflytop/sgs/app/service/device/DeviceInitService.java @@ -6,7 +6,7 @@ import com.iflytop.sgs.common.enums.HeatModuleCode; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.stereotype.Service; import java.util.List; @@ -16,6 +16,7 @@ import java.util.List; @RequiredArgsConstructor public class DeviceInitService { private final DeviceStateService deviceStateService; + private final ObjectProvider heatModuleStateProvider; @PostConstruct public void init() { @@ -38,11 +39,11 @@ public class DeviceInitService { } public void initDeviceState() { + //初始化加热模块属性 DeviceState deviceState = deviceStateService.getDeviceState(); List heatArea = deviceState.getHeatModule(); for (HeatModuleCode code : HeatModuleCode.values()) { - heatArea.add(new HeatModuleState(code)); + heatArea.add(heatModuleStateProvider.getObject(code)); } } - } diff --git a/src/main/java/com/iflytop/sgs/app/service/device/DeviceStateService.java b/src/main/java/com/iflytop/sgs/app/service/device/DeviceStateService.java index 523a62e..aebadad 100644 --- a/src/main/java/com/iflytop/sgs/app/service/device/DeviceStateService.java +++ b/src/main/java/com/iflytop/sgs/app/service/device/DeviceStateService.java @@ -15,7 +15,7 @@ import java.util.concurrent.atomic.AtomicReference; @RequiredArgsConstructor public class DeviceStateService { @Getter - private final DeviceState deviceState = new DeviceState(); + private final DeviceState deviceState; @Getter private final AtomicReference commandMutexState = new AtomicReference<>(new CommandMutexState()); diff --git a/src/main/java/com/iflytop/sgs/common/result/ResultCode.java b/src/main/java/com/iflytop/sgs/common/result/ResultCode.java index eb02110..021c1d6 100644 --- a/src/main/java/com/iflytop/sgs/common/result/ResultCode.java +++ b/src/main/java/com/iflytop/sgs/common/result/ResultCode.java @@ -36,10 +36,10 @@ public enum ResultCode implements IResultCode, Serializable { INVALID_CREDENTIALS("4002", "用户名或密码错误"), OPERATION_NOT_ALLOWED("4003", "业务操作不允许"), DATA_ALREADY_EXISTS("4004", "数据已存在"), - CRAFT_RUNNING("4101", "工艺正在执行"), CRAFT_CONTEXT_NULL("4102", "请先配置该加热区工艺"), CRAFT_CONTAINER_NOT_FOUND("4005", "工艺未找到对应溶液容器"), + CRAFT_IDLE_HEAT_MODULE_NOT_FOUND("4005", "工艺未找到空闲的加热模块"), //============================ 5xxx:系统 & 第三方 ============================ SYSTEM_ERROR("5000", "系统内部错误"), SERVICE_UNAVAILABLE("5001", "服务暂不可用"),