From 7a57a082555ae7676d210f39872ef1e40a542208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=B1=9F=E7=8E=AE?= Date: Thu, 20 Jul 2023 16:56:31 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E8=BF=9B=E7=AA=91=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lnsh/lnsh_kiln_truss/ItemProtocol.java | 37 +++++--- .../LnshKilnTrussDefination.java | 10 +-- .../LnshKilnTrussDeviceDriver.java | 81 +++++++++++++++--- .../lnsh_press/LnshPressDeviceDriver.java | 2 +- .../wms/service/impl/AcsToWmsServiceImpl.java | 22 +++-- .../wms/ext/acs/rest/AcsToWmsController.java | 8 ++ .../wms/ext/acs/service/AcsToWmsService.java | 2 + .../acs/service/impl/AcsToWmsServiceImpl.java | 19 ++++ .../src/main/java/org/nl/wms/wms.xls | Bin 281088 -> 281088 bytes 9 files changed, 136 insertions(+), 45 deletions(-) diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/ItemProtocol.java index 1a42043..1ef0aa2 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/ItemProtocol.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/ItemProtocol.java @@ -19,6 +19,9 @@ public class ItemProtocol { public static String item_standby_time = "standby_time"; public static String item_production_time = "production_time"; public static String item_error_time = "error_time"; + public static String item_kiln_number = "kiln_number"; + public static String item_barcode = "barcode"; + public static String item_to_command = "to_command"; public static String item_to_target = "to_target"; public static String item_to_task = "to_task"; @@ -42,6 +45,14 @@ public class ItemProtocol { return this.getOpcIntegerValue(item_status); } + public int getKiln_number() { + return this.getOpcIntegerValue(item_kiln_number); + } + + public int getBarcode() { + return this.getOpcIntegerValue(item_barcode); + } + public String getOpen_time() { return this.getOpcStringValue(item_open_time); } @@ -99,22 +110,24 @@ public class ItemProtocol { } public static List getReadableItemDtos() { - ArrayList list = new ArrayList(); - list.add(new ItemDto(item_heartbeat, "心跳", "DB1.B0")); - list.add(new ItemDto(item_mode, "工作模式", "DB1.B1", Boolean.valueOf(true))); - list.add(new ItemDto(item_status, "设备状态", "DB1.B2")); - list.add(new ItemDto(item_open_time, "开机时间", "DB1.STRING4.50")); - list.add(new ItemDto(item_standby_time, "待机时间", "DB1.D56")); - list.add(new ItemDto(item_production_time, "生产时间", "DB1.D60")); - list.add(new ItemDto(item_error_time, "故障时间", "DB1.D64")); + ArrayList list = new ArrayList<>(); + list.add(new ItemDto(item_heartbeat, "心跳", "DB100.B0")); + list.add(new ItemDto(item_mode, "工作模式", "DB100.B1", Boolean.TRUE)); + list.add(new ItemDto(item_status, "设备状态", "DB100.B2")); + list.add(new ItemDto(item_kiln_number, "进窑窑号", "DB100.D4")); + list.add(new ItemDto(item_barcode, "条码", "DB100.W8")); + list.add(new ItemDto(item_open_time, "开机时间", "DB100.STRING10.50")); + list.add(new ItemDto(item_standby_time, "待机时间", "DB100.D62")); + list.add(new ItemDto(item_production_time, "生产时间", "DB100.D66")); + list.add(new ItemDto(item_error_time, "故障时间", "DB100.D70")); return list; } public static List getWriteableItemDtos() { - ArrayList list = new ArrayList(); - list.add(new ItemDto(item_to_command, "下发指令", "DB2.W0", Boolean.valueOf(true))); - list.add(new ItemDto(item_to_target, "下发目标站", "DB2.W2")); - list.add(new ItemDto(item_to_task, "下发任务号", "DB2.D4")); + ArrayList list = new ArrayList<>(); + list.add(new ItemDto(item_to_command, "下发指令", "DB101.W0", Boolean.TRUE)); + list.add(new ItemDto(item_to_target, "下发目标站", "DB101.W2")); + list.add(new ItemDto(item_to_task, "下发任务号", "DB101.D4")); return list; } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/LnshKilnTrussDefination.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/LnshKilnTrussDefination.java index 5043ddd..03e831f 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/LnshKilnTrussDefination.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/LnshKilnTrussDefination.java @@ -54,15 +54,7 @@ public class LnshKilnTrussDefination implements OpcDeviceDriverDefination { } public static List getReadableItemDtos2() { - ArrayList list = new ArrayList(); - list.add(new ItemDto(ItemProtocol.item_heartbeat, "心跳", "DB1.B0")); - list.add(new ItemDto(ItemProtocol.item_mode, "工作模式", "DB1.B1", Boolean.valueOf(true))); - list.add(new ItemDto(ItemProtocol.item_status, "设备状态", "DB1.B2")); - list.add(new ItemDto(ItemProtocol.item_open_time, "开机时间", "DB1.STRING4.50")); - list.add(new ItemDto(ItemProtocol.item_standby_time, "待机时间", "DB1.D56")); - list.add(new ItemDto(ItemProtocol.item_production_time, "生产时间", "DB1.D60")); - list.add(new ItemDto(ItemProtocol.item_error_time, "故障时间", "DB1.D64")); - return list; + return ItemProtocol.getReadableItemDtos(); } @Override diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/LnshKilnTrussDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/LnshKilnTrussDeviceDriver.java index cbec0bc..d2c77d2 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/LnshKilnTrussDeviceDriver.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_kiln_truss/LnshKilnTrussDeviceDriver.java @@ -1,15 +1,19 @@ package org.nl.acs.device_driver.lnsh.lnsh_kiln_truss; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpResponse; import com.alibaba.fastjson.JSONObject; import lombok.Getter; import lombok.Setter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ReadUtil; import org.nl.acs.device.service.DeviceService; import org.nl.acs.device_driver.DeviceDriver; import org.nl.acs.device_driver.RouteableDeviceDriver; import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver; import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; +import org.nl.acs.ext.wms.service.AcsToWmsService; import org.nl.acs.instruction.service.InstructionService; import org.nl.acs.instruction.service.dto.Instruction; import org.nl.acs.log.service.DeviceExecuteLogService; @@ -18,10 +22,14 @@ import org.nl.acs.opc.Device; import org.nl.acs.route.service.RouteLineService; import org.nl.acs.task.service.TaskService; import org.nl.modules.wql.util.SpringContextHolder; +import org.openscada.opc.lib.da.Server; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 晟华入出窑桁架 @@ -43,6 +51,8 @@ public class LnshKilnTrussDeviceDriver extends AbstractOpcDeviceDriver implement DeviceExecuteLogService logServer = SpringContextHolder.getBean("deviceExecuteLogServiceImpl"); + AcsToWmsService acsToWmsService = SpringContextHolder.getBean("acsToWmsServiceImpl"); + String device_code; int mode = 0; int error = 0; @@ -54,6 +64,8 @@ public class LnshKilnTrussDeviceDriver extends AbstractOpcDeviceDriver implement int hasGoods = 0; Boolean iserror = false; + private Date instruction_require_time = new Date(); + private int instruction_require_time_out = 3000; boolean requireSucess = false; private Date checkHeartbeattime = new Date(); @@ -68,6 +80,11 @@ public class LnshKilnTrussDeviceDriver extends AbstractOpcDeviceDriver implement int status = 0; int last_status = 0; + int kiln_number = 0; + int last_kiln_number = 0; + int barcode = 0; + int last_barcode = 0; + String open_time = "0"; String last_open_time = "0"; int standby_time = 0; @@ -85,11 +102,12 @@ public class LnshKilnTrussDeviceDriver extends AbstractOpcDeviceDriver implement @Override public void execute() { - String message = null; try { device_code = this.getDeviceCode(); mode = this.itemProtocol.getMode(); status = this.itemProtocol.getStatus(); + kiln_number = this.itemProtocol.getKiln_number(); + barcode = this.itemProtocol.getBarcode(); open_time = this.itemProtocol.getOpen_time(); standby_time = this.itemProtocol.getStandby_time(); production_time = this.itemProtocol.getProduction_time(); @@ -104,6 +122,14 @@ public class LnshKilnTrussDeviceDriver extends AbstractOpcDeviceDriver implement logServer.deviceItemValue(this.device_code,"status" ,String.valueOf(status)); logServer.deviceExecuteLog(this.device_code,"","","信号status:" + last_status + " -> " + status); } + if (kiln_number != last_kiln_number) { + logServer.deviceItemValue(this.device_code,"kiln_number" ,String.valueOf(kiln_number)); + logServer.deviceExecuteLog(this.device_code,"","","信号kiln_number:" + last_kiln_number + " -> " + kiln_number); + } + if (barcode != last_barcode) { + logServer.deviceItemValue(this.device_code,"barcode" ,String.valueOf(barcode)); + logServer.deviceExecuteLog(this.device_code,"","","信号barcode:" + last_barcode + " -> " + barcode); + } if (!open_time.equals(last_open_time)) { logServer.deviceItemValue(this.device_code,"open_time" ,String.valueOf(open_time)); logServer.deviceExecuteLog(this.device_code,"","","信号open_time:" + last_open_time + " -> " + open_time); @@ -148,25 +174,22 @@ public class LnshKilnTrussDeviceDriver extends AbstractOpcDeviceDriver implement this.setIsonline(true); this.setIserror(false); message = ""; - Instruction instruction = null; - List toInstructions; switch (mode) { case 1: log.debug("设备运转模式:等待工作"); break; - case 2: - - break; - case 3: - - break; - case 4: - break; + case 16: + // 进窑确认 + if (!requireSucess && barcode != 0 && kiln_number != 0) { + this.inKiln(); + } } } last_mode = mode; last_status = status; + last_kiln_number = kiln_number; + last_barcode = barcode; last_open_time = open_time; last_standby_time = standby_time; last_production_time = production_time; @@ -182,6 +205,42 @@ public class LnshKilnTrussDeviceDriver extends AbstractOpcDeviceDriver implement } } + public void writing(int command) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + org.nl.acs.device_driver.lnsh.lnsh_press.ItemProtocol.item_to_command; + + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + itemMap.put(to_command, command); + ReadUtil.write(itemMap, server); + ReadUtil.write(itemMap, server); + server.disconnect(); + logServer.deviceExecuteLog(this.device_code, "", "", "to_command 写入 " + command); + } + + public synchronized void inKiln() { + Date date = new Date(); + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + } else { + this.instruction_require_time = date; + JSONObject param = new JSONObject(); + param.put("kiln_number", kiln_number); + param.put("vehicle_code", barcode); + HttpResponse response = acsToWmsService.inKiln(param); + if (ObjectUtil.isNotEmpty(response)) { + if (response.getStatus() == HttpStatus.OK.value()) { + JSONObject jsonObject = JSONObject.parseObject(response.body()); + if (ObjectUtil.isNotEmpty(jsonObject) && "200".equals(jsonObject.getString("status"))) { + this.writing(this.mode); + this.requireSucess = true; + } + } + } + } + } + @Override public JSONObject getDeviceStatusName() throws Exception { String mode; diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_press/LnshPressDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_press/LnshPressDeviceDriver.java index b55e6e3..7cdebe7 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_press/LnshPressDeviceDriver.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/lnsh/lnsh_press/LnshPressDeviceDriver.java @@ -76,7 +76,7 @@ public class LnshPressDeviceDriver extends AbstractOpcDeviceDriver implements De private Date instruction_require_time = new Date(); private Date instruction_finished_time = new Date(); - private int instruction_require_time_out; + private int instruction_require_time_out = 3000; boolean requireSucess = false; private int instruction_finished_time_out; diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/AcsToWmsServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/AcsToWmsServiceImpl.java index a854056..4ca1dd2 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/AcsToWmsServiceImpl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/AcsToWmsServiceImpl.java @@ -368,32 +368,30 @@ public class AcsToWmsServiceImpl implements AcsToWmsService { } @Override - public HttpResponse inKiln(JSONObject json) { + public HttpResponse inKiln(JSONObject param) { try { MDC.put(log_file_type, log_type); String wmsurl = acsConfigService.findByCode(AcsConfig.WMSURL).getValue(); + + HttpResponse result = null; + log.info("inKiln - 请求参数 {}", param); AddressDto addressDto = addressService.findByCode("inKiln"); String methods_url = addressDto.getMethods_url(); - String url = wmsurl + methods_url; - - log.info("inKiln - 请求参数 {}", json.toString()); - HttpResponse result = null; try { - result = HttpRequest.post(url) - .header("Authorization", token) - .body(String.valueOf(json)) + result = HttpRequest + .post(wmsurl + methods_url) + .body(param.toJSONString()) .execute(); - System.out.println(result); log.info("inKiln - 返回参数 {}", result.body()); } catch (Exception e) { - System.out.println(e.getMessage()); + String msg = e.getMessage(); + //网络不通 + System.out.println(msg); } return result; - } finally { MDC.remove(log_file_type); } - } @Override diff --git a/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/rest/AcsToWmsController.java b/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/rest/AcsToWmsController.java index 69a5009..d8f3d7f 100644 --- a/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/rest/AcsToWmsController.java +++ b/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/rest/AcsToWmsController.java @@ -205,4 +205,12 @@ public class AcsToWmsController { public ResponseEntity mark(@RequestBody JSONObject whereJson) { return new ResponseEntity<>(acsToWmsService.mark(whereJson), HttpStatus.OK); } + + @PostMapping("/inKiln") + @Log("反馈进窑分配") + @ApiOperation("反馈进窑分配") + @SaIgnore + public ResponseEntity inKiln(@RequestBody JSONObject param) { + return ResponseEntity.ok(acsToWmsService.inKiln(param)); + } } diff --git a/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/service/AcsToWmsService.java b/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/service/AcsToWmsService.java index bb1afd4..8abf1d5 100644 --- a/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/service/AcsToWmsService.java +++ b/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/service/AcsToWmsService.java @@ -118,4 +118,6 @@ public interface AcsToWmsService { JSONObject mark(JSONObject whereJson); + + JSONObject inKiln(JSONObject param); } diff --git a/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/service/impl/AcsToWmsServiceImpl.java b/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/service/impl/AcsToWmsServiceImpl.java index 30879e0..fff7260 100644 --- a/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/service/impl/AcsToWmsServiceImpl.java +++ b/lms/nladmin-system/src/main/java/org/nl/wms/ext/acs/service/impl/AcsToWmsServiceImpl.java @@ -749,4 +749,23 @@ public class AcsToWmsServiceImpl implements AcsToWmsService { throw new BadRequestException("[" + VehicleType.get(String.valueOf(vehicle_type)).label() + "] [" + vehicle_code + "] 无信息!"); } } + + @Override + public JSONObject inKiln(JSONObject param) { + String vehicle_code = TaskUtils.formatVehicleCode(param.getString("vehicle_code")); + if (StrUtil.isNotBlank(vehicle_code)) { + String kiln_number = param.getString("kiln_number"); + if (StrUtil.isNotBlank(kiln_number)) { + JSONObject vd_update = new JSONObject(); + vd_update.put("kiln_number", "Y0" + kiln_number); + vd_update.put("in_kiln_time", DateUtil.now()); + WQLObject.getWQLObject("st_ivt_vehicle_detail").update(vd_update, "is_delete = '0' AND vehicle_code = '" + vehicle_code + "'"); + } + } + + JSONObject result = new JSONObject(); + result.put("status", HttpStatus.OK.value()); + result.put("message", "反馈成功!"); + return result; + } } diff --git a/lms/nladmin-system/src/main/java/org/nl/wms/wms.xls b/lms/nladmin-system/src/main/java/org/nl/wms/wms.xls index 22eadec379f69509d738bf421be083f65e7389d6..a639acf0c7fc8d49c08a0a7d8fc12230b4ccc388 100644 GIT binary patch delta 13255 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