From 5191851edd1619a75ac507b2a1c92ec1708a16a5 Mon Sep 17 00:00:00 2001 From: sige Date: Fri, 12 Apr 2024 21:12:11 +0800 Subject: [PATCH] ~ --- app.db | Bin 299008 -> 299008 bytes .../com/iflytop/digester/DigestionTaskThread.java | 119 +++++++++++++++------ .../digester/controller/CameraController.java | 15 +++ .../controller/DigestionTaskController.java | 9 +- .../digester/controller/LiquidController.java | 4 +- .../deviceinstance/HeatingTurntableInstance.java | 5 + .../deviceinstance/LiquidAdditionLiquid.java | 15 +++ .../deviceinstance/TransferRobotArmInstance.java | 16 ++- .../iflytop/digester/model/MdbDigestionTask.java | 5 +- .../dao/model/UfMdbNotification.java | 15 +++ .../dao/model/UfMdbRuntimeVariable.java | 10 +- 11 files changed, 170 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/iflytop/digester/controller/CameraController.java diff --git a/app.db b/app.db index e69323887f8a91b3a48e3120e2752fe76343e479..6a0fe3416876ec59f6e4387a5bd25e5aec4991af 100644 GIT binary patch literal 299008 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 b)bC` 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 YD6oLIJDp&i5L%=u>X53pU(Kif7fW3Fi2wiq delta 931 zcmZWmU2GIp6u#%q%f}u&YoB z(aYpEnI*D*UGLCtsDG%l%Ad+Y`0sE%^iAlLv_kw*j0->G-*G$q0Kh*yU~YIQ=8q1Z z2>W+3^EkA9Pbl)N<<4(ucXtd%n_Ay`d3QKsSui#3zCX|l5Bc8?bc6eS()Dj_>J(;R z4ksSdHH4^AMOs|{itHm{^{oE7zEZo=bV)0zh|bg9R8Xq^8g^Xqt4E%}@)szc-E2+l zbSrOk`|+_MkhX`UY>(SHy5651&*FfVEtEypMfLNDE|M*zOsB|Raz#H+n@B57(VG4> zeSzH4f8(?Vb+3FGM88tq5ALJY9!?wepRbLvSby3~e!!HvJO-(095oi^pRmf4!{Ek+yXmATKOnQ?9HhDj3AbTI_aMD|* zz+^tn53;@c4|%Ws15xig4ORz_$sn}1y^?T-mgQG4C z0<2OowGsW8+VlxdpP~?T*RW2{9)b5%y`jB?=n{W=o4&ahq-^9!OCgspSm_OUBWb2= zBbBjpM&2s+8>W*ot#ro8C7pDkR2nJ$^4W$%@&Z6LKoI$D#a)d2G| zY4K1h|((@x1Jlu x;-?}On6#E-dp(We5$N#77+wuh{auFlJrdwvx>&|+Y7Wn^IXrxEStvJ_@gH)x_M`v+ diff --git a/src/main/java/com/iflytop/digester/DigestionTaskThread.java b/src/main/java/com/iflytop/digester/DigestionTaskThread.java index 05eea2a..18b8a43 100644 --- a/src/main/java/com/iflytop/digester/DigestionTaskThread.java +++ b/src/main/java/com/iflytop/digester/DigestionTaskThread.java @@ -94,25 +94,38 @@ public class DigestionTaskThread extends Thread { public void run() { try { this.prepare(); + + // 解析消解配方并取出首轮和末轮配置 var rounds = this.solution.getDigestionRounds(); - var firstRound = rounds.remove(0); - var lastRound = rounds.remove(rounds.size() - 1); + MdbDigestionSolution.DigestionSolutionRound firstRound = null; + if ( !rounds.isEmpty() && rounds.size() > 1 ) { + firstRound = rounds.remove(0); + } + MdbDigestionSolution.DigestionSolutionRound lastRound = null; + if ( !rounds.isEmpty() ) { + lastRound = rounds.remove(rounds.size() - 1); + } // 执行第一轮 - this.executeRound(firstRound); + if ( null != firstRound ) { + this.executeRound(firstRound); + } // 执行中间轮 for (var round : rounds) { this.executeRound(round); } // 执行最后一轮 - this.executeLastRound(lastRound); + if ( null != lastRound ) { + this.executeLastRound(lastRound); + } this.errorProcessThread.join(); this.updateTaskStatus("Finish", "消解任务结束"); - this.finishCallback.callback(this); } catch (Exception e) { this.updateTaskStatus("Error", e.getMessage()); UfMdbNotification.error("消解任务执行失败 : " + e.getMessage()); + } finally { + this.finishCallback.callback(this); } } @@ -123,17 +136,23 @@ public class DigestionTaskThread extends Thread { var device = Device.getInstance(); // 分配加热位 - this.heatingSlot = device.heatingTurntable.allocSlot(this.taskModel.batchNo); + if ( "manual".equals(this.taskModel.mode) ) { + this.heatingSlot = device.heatingTurntable.getSlotByIndex(this.taskModel.heatingSlotIndex); + } else { + this.heatingSlot = device.heatingTurntable.allocSlot(this.taskModel.batchNo); + } this.heatingSlot.setTubes(this.taskModel.getTubes()); this.taskModel.heatingSlotIndex = this.heatingSlot.index; this.taskModel.save(); - // 打开门 - device.door.open(); - // 等待放入试管架 - this.waitForTubeRackPutIn(false); - // 关闭门 - device.door.close(); + if ( "auto".equals(this.taskModel.mode) ) { + // 打开门 + device.door.open(); + // 等待放入试管架 + this.waitForTubeRackPutIn(); + // 关闭门 + device.door.close(); + } } // 检查试管 @@ -171,7 +190,7 @@ public class DigestionTaskThread extends Thread { if ( !this.errorTubeIndexes.isEmpty() ) { var device = Device.getInstance(); // 等待放入空试管架 - this.waitForTubeRackPutIn(true); + this.waitForEmptyTubeRackPutIn(); // 取出剩余异常试管 device.transferArm.takeOutTubesFromErrorSlot(this.errorTubeIndexes); // 等待取出试管架 @@ -268,17 +287,19 @@ public class DigestionTaskThread extends Thread { device.liquidAddition.addLiquidToTubes(this.heatingSlot.getExistTubeIndexes(), "water", digestionRound.waterVolume); } - // 正常消解结束 - // 移动到加液盘 - device.transferArm.moveTubeRackToLiquidPlate(this.heatingSlot.index); - // 打开门 - device.door.open(); - // 等待取出 - this.waitForTubeRackTakeOut(); - // 关闭门 - device.door.close(); - // 释放加热位 - this.heatingSlot.setTubeRackNo(null); + // 正常消解结束; + if ( "auto".equals(this.taskModel.mode) ) { + // 移动到加液盘 + device.transferArm.moveTubeRackToLiquidPlate(this.heatingSlot.index); + // 打开门 + device.door.open(); + // 等待取出 + this.waitForTubeRackTakeOut(); + // 关闭门 + device.door.close(); + // 释放加热位 + this.heatingSlot.setTubeRackNo(null); + } } // 执行消解异常处理配置 @@ -311,7 +332,7 @@ public class DigestionTaskThread extends Thread { // 将试管架放入异常处理区域 device.transferArm.moveTubeRackToHeatingTurntable(this.heatingSlot.index); // 等待放入空试管架 - this.waitForTubeRackPutIn(true); + this.waitForEmptyTubeRackPutIn(); // 取出消解完成的试管 device.transferArm.takeOutTubesFromErrorSlot(this.finishedErrorTubeIndexes); // 等待取出试管架 @@ -321,14 +342,37 @@ public class DigestionTaskThread extends Thread { } // 等待放入试管架 - private void waitForTubeRackPutIn( Boolean requestEmptyTubeRack ) { - if ( requestEmptyTubeRack ) { - this.manager.sendMessageToTransBot("EmptyTubeRackPutIn", Map.of("batchNo", this.taskModel.batchNo)); + private void waitForTubeRackPutIn() { + this.updateTaskStatus("TubeRackPutInWait", "等待放入试管架"); + + // 发送放入试管架消息 + Map message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId); + this.manager.sendMessageToTransBot("TubeRackPutIn", message); + + // 等待试管架放入完成 + synchronized ( this.tubeRackPutInWaitLock ) { + try { + this.tubeRackPutInWaitLock.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + this.updateTaskStatus("TubeRackPutInWaitDone", "试管架已放入"); + } + + // 等待放入试管架 + private void waitForEmptyTubeRackPutIn() { + this.updateTaskStatus("TubeRackPutInWait", "等待放入空试管架"); + + // 发送放入试管架消息 + Map message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId); + if ( "auto".equals(this.taskModel.mode) ) { + this.manager.sendMessageToTransBot("EmptyTubeRackPutIn", message); } else { - this.manager.sendMessageToTransBot("TubeRackPutIn", Map.of("batchNo", this.taskModel.batchNo)); + UfMdbNotification.action("EmptyTubeRackPutIn", message); } - this.updateTaskStatus("TubeRackPutInWait", "等待放入试管架"); + // 等待试管架放入完成 synchronized ( this.tubeRackPutInWaitLock ) { try { this.tubeRackPutInWaitLock.wait(); @@ -341,8 +385,15 @@ public class DigestionTaskThread extends Thread { // 等待取出试管架 private void waitForTubeRackTakeOut() { - this.manager.sendMessageToTransBot("TubeRackTakeOut", Map.of("batchNo", this.taskModel.batchNo)); this.updateTaskStatus("TubeRackTakeOutWait", "等待取出试管架"); + + Map message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId); + if ( "auto".equals(this.taskModel.mode) ) { + this.manager.sendMessageToTransBot("TubeRackTakeOut", message); + } else { + UfMdbNotification.action("TubeRackTakeOut", message); + } + synchronized ( this.tubeRackTakeOutWaitLock ) { try { this.tubeRackTakeOutWaitLock.wait(); @@ -356,6 +407,9 @@ public class DigestionTaskThread extends Thread { // 拍照检查试管 private void takeShotAndCheckErrorTubes() { this.updateTaskStatus("TubeCheck", "拍照检查试管,等待确认异常试管"); + Map message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId); + UfMdbNotification.action("TubeCheck", message); + this.errorTubeIndexes.clear(); synchronized ( this.errorTubeIndexes ) { try { @@ -370,6 +424,9 @@ public class DigestionTaskThread extends Thread { // 拍照检查试管 private void takeShotAndCheckFinishedTubes() { this.updateTaskStatus("ErrorTubeCheck", "拍照检查异常试管,等待确认完成试管"); + Map message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId); + UfMdbNotification.action("ErrorTubeCheck", message); + this.finishedErrorTubeIndexes.clear(); synchronized ( this.finishedErrorTubeIndexes ) { try { diff --git a/src/main/java/com/iflytop/digester/controller/CameraController.java b/src/main/java/com/iflytop/digester/controller/CameraController.java new file mode 100644 index 0000000..3e5a0ab --- /dev/null +++ b/src/main/java/com/iflytop/digester/controller/CameraController.java @@ -0,0 +1,15 @@ +package com.iflytop.digester.controller; +import com.iflytop.digester.underframework.controller.UfApiControllerBase; +import com.iflytop.digester.underframework.controller.UfApiResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import java.util.Map; +@Controller +public class CameraController extends UfApiControllerBase { + @ResponseBody + @PostMapping("/api/camera/take-shot") + public UfApiResponse takeShot() { + return this.success(Map.of("data", "https://avatars.githubusercontent.com/u/53512912?v=4")); + } +} diff --git a/src/main/java/com/iflytop/digester/controller/DigestionTaskController.java b/src/main/java/com/iflytop/digester/controller/DigestionTaskController.java index eab13a0..f445e79 100644 --- a/src/main/java/com/iflytop/digester/controller/DigestionTaskController.java +++ b/src/main/java/com/iflytop/digester/controller/DigestionTaskController.java @@ -7,6 +7,7 @@ import com.iflytop.digester.underframework.util.UfJsonHelper; import com.iflytop.digester.underframework.controller.UfApiControllerBase; import com.iflytop.digester.underframework.controller.UfApiResponse; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -20,11 +21,13 @@ public class DigestionTaskController extends UfApiControllerBase { @ResponseBody @PostMapping("/api/digestion-task/start") - public UfApiResponse start(@RequestBody Map params) { + public UfApiResponse start(HttpServletRequest request, @RequestBody Map params) { String taskId = (String)params.get("taskId"); String name = (String)params.get("name"); String batchNo = (String)params.get("batchNo"); List> tubes = (List>)params.get("tubes"); + String mode = (String)params.get("mode"); + Integer slotIndex = (Integer)params.get("slotIndex"); var digestion = UfActiveRecord.findOne(MdbDigestionSolution.class, Map.of("name", name)); if ( null == digestion ) { @@ -39,7 +42,9 @@ public class DigestionTaskController extends UfApiControllerBase { task.status = "pending"; task.message = "等待中"; task.startedAt = (int)(System.currentTimeMillis() / 1000); - task.startedBy = 0; + task.startedBy = this.getUserFromRequest(request).id; + task.mode = mode; + task.heatingSlotIndex = slotIndex; task.save(); this.taskManager.startTask(task); diff --git a/src/main/java/com/iflytop/digester/controller/LiquidController.java b/src/main/java/com/iflytop/digester/controller/LiquidController.java index 783431f..71bfc3e 100644 --- a/src/main/java/com/iflytop/digester/controller/LiquidController.java +++ b/src/main/java/com/iflytop/digester/controller/LiquidController.java @@ -26,8 +26,8 @@ public class LiquidController extends UfApiControllerBase { Integer bucketIndex = (Integer)params.get("index"); String liquidType = (String)params.get("type"); var bucket = this.device.liquidAddition.getLiquidByIndex(bucketIndex); - bucket.type = liquidType; - bucket.volume = bucket.totalVolume; + bucket.setType(liquidType); + bucket.setVolume(bucket.totalVolume); return this.success(); } } diff --git a/src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java b/src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java index 7759a1d..d0fcd0e 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java @@ -22,6 +22,11 @@ public class HeatingTurntableInstance { return slots; } + // 根据索引获取槽位 + public HeatingTurntableSlot getSlotByIndex(Integer index) { + return slots.get(index); + } + public HeatingTurntableSlot getSlotByLiquidPlateTubeRack() { for (HeatingTurntableSlot slot : slots) { if (null != slot.tubeRackNo && slot.tubeRackLocation.equals("liquid-plate")) { diff --git a/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java b/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java index 90ec9e3..aed09ad 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java @@ -1,4 +1,7 @@ package com.iflytop.digester.deviceinstance; + +import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable; + public class LiquidAdditionLiquid { // bucket index public Integer bucketIndex; @@ -8,4 +11,16 @@ public class LiquidAdditionLiquid { public Integer volume; // total volume public Integer totalVolume; + + // set type + public void setType( String type ) { + this.type = type; + UfMdbRuntimeVariable.setString(String.format("LiquidBucketType.%d", this.bucketIndex), type); + } + + // set volume + public void setVolume( Integer volume ) { + this.volume = volume; + UfMdbRuntimeVariable.setInteger(String.format("LiquidBucketVolume.%d", this.bucketIndex), volume); + } } diff --git a/src/main/java/com/iflytop/digester/deviceinstance/TransferRobotArmInstance.java b/src/main/java/com/iflytop/digester/deviceinstance/TransferRobotArmInstance.java index ac9734e..4c5d01c 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/TransferRobotArmInstance.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/TransferRobotArmInstance.java @@ -3,6 +3,8 @@ import com.iflytop.digester.underframework.UfCmdSnippetExecutor; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +import java.util.Map; + @Component public class TransferRobotArmInstance { // 等待锁队列 @@ -16,7 +18,12 @@ public class TransferRobotArmInstance { // 执行从异常槽位取出试管 UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlotStart"); for (Integer tubeIndex : tubeIndexes) { - UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlot." + tubeIndex); + UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlot", Map.of( + "MotorLiquidPlatePos", 100, + "MotorArmLeftRightSrcPos", 100, + "MotorArmLeftRightDstPos", 100, + "MotorHeatingTurntablePos", 100 + )); } UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlotEnd"); @@ -31,7 +38,12 @@ public class TransferRobotArmInstance { // 执行移动试管到异常槽位 UfCmdSnippetExecutor.execute("TubeMoveToErrorSlotStart"); for (Integer tubeIndex : tubeIndexes) { - UfCmdSnippetExecutor.execute("TubeMoveToErrorSlot." + tubeIndex); + UfCmdSnippetExecutor.execute("TubeMoveToErrorSlot", Map.of( + "MotorLiquidPlatePos", 100, + "MotorArmLeftRightSrcPos", 100, + "MotorArmLeftRightDstPos", 100, + "MotorHeatingTurntablePos", 100 + )); } UfCmdSnippetExecutor.execute("TubeMoveToErrorSlotEnd"); diff --git a/src/main/java/com/iflytop/digester/model/MdbDigestionTask.java b/src/main/java/com/iflytop/digester/model/MdbDigestionTask.java index a0144ce..0fcd773 100644 --- a/src/main/java/com/iflytop/digester/model/MdbDigestionTask.java +++ b/src/main/java/com/iflytop/digester/model/MdbDigestionTask.java @@ -30,7 +30,7 @@ public class MdbDigestionTask extends UfActiveRecord { public Integer startedAt; @UfActiveRecordField - public Integer startedBy; + public String startedBy; @UfActiveRecordField public Integer finishedAt = 0; @@ -38,6 +38,9 @@ public class MdbDigestionTask extends UfActiveRecord { @UfActiveRecordField public Integer heatingSlotIndex = -1; + @UfActiveRecordField + public String mode; + // get table name public static String getTableName() { return "app_digestion_tasks"; diff --git a/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbNotification.java b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbNotification.java index 01e0040..48ff79a 100644 --- a/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbNotification.java +++ b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbNotification.java @@ -1,6 +1,10 @@ package com.iflytop.digester.underframework.dao.model; import com.iflytop.digester.underframework.dao.record.UfActiveRecord; import com.iflytop.digester.underframework.dao.record.UfActiveRecordField; +import com.iflytop.digester.underframework.util.UfJsonHelper; + +import java.util.Map; + public class UfMdbNotification extends UfActiveRecord { @UfActiveRecordField public String type; @@ -59,4 +63,15 @@ public class UfMdbNotification extends UfActiveRecord { notification.status = "new"; notification.save(); } + + // notify action + public static void action( String action, Map params) { + var data = Map.of("action", action, "params", params); + var dataJson = UfJsonHelper.objectToJson(data); + var notification = new UfMdbNotification(); + notification.type = "action"; + notification.data = dataJson; + notification.status = "new"; + notification.save(); + } } diff --git a/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java index 3f4b3ce..5ce19d7 100644 --- a/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java +++ b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java @@ -42,19 +42,19 @@ public class UfMdbRuntimeVariable extends UfActiveRecord { } // set string - public static void setString(String value, String name, Object ... args ) { - var variable = UfMdbRuntimeVariable.getVariable(name, args); + public static void setString(String name, String value) { + var variable = UfActiveRecord.findOne(UfMdbRuntimeVariable.class, Map.of("key", name)); if ( null == variable ) { variable = new UfMdbRuntimeVariable(); - variable.key = UfMdbRuntimeVariable.buildKey(name, args); + variable.key = name; } variable.value = value; variable.save(); } // set integer - public static void setInteger(Integer value, String name, Object ... args ) { - UfMdbRuntimeVariable.setString(value.toString(), name, args); + public static void setInteger(String name, Integer value) { + UfMdbRuntimeVariable.setString(name, value.toString()); } // remove