feat():OPC 通讯测试和订阅事件

This commit is contained in:
Penknife
2025-09-12 16:13:41 +08:00
parent 74e87ce652
commit 790f9d81e0
7 changed files with 386 additions and 29 deletions

View File

@@ -1,13 +1,28 @@
package com.fizz.business.comm.OPC;
import com.fizz.business.constants.enums.ExitCutTypeEnum;
import com.fizz.business.constants.enums.OpcMessageType;
import com.fizz.business.domain.msg.*;
import com.fizz.business.service.hanle.OpcReceiverHandler;
import com.kangaroohy.milo.model.ReadWriteEntity;
import com.kangaroohy.milo.service.MiloService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.fizz.business.service.manager.OpcMessageIdsManager.*;
//@Component
@Slf4j
@@ -15,25 +30,118 @@ public class MessageSubscriptionRunner implements ApplicationRunner {
@Resource
private MiloService miloService;
@Resource
private OpcReceiverHandler opcReceiverHandler;
@Override
public void run(ApplicationArguments args) {
subEntryMove();
sub();
}
private void subEntryMove() {
private void sub() {
try {
List<String> ids = Lists.newArrayList();
ids.add("GA.T1.T1001R");
ids.add("GA.T1.String");
miloService.subscriptionFromOpcUa(ids, (id, value) -> {
log.info("subscription 点位:{} 订阅到消息:{}", id, value);
LocalDateTime localDateTime = LocalDateTime.now();
AtomicBoolean isFirstRun = new AtomicBoolean(false);
//入口移动,剪切、出口移动、出口称重
miloService.subscriptionFromOpcUa(msgTriggers, 500,(id, value) -> {
if(!isFirstRun.get()){
Duration duration = Duration.between(localDateTime, LocalDateTime.now());
if(duration.getSeconds() > 10){
isFirstRun.set(true);
}else{
return;
}
}
String nodeName = id.getNodeId().toString();
if (nodeName.contains(entryMoveIds.get("trigger"))) {
log.info("接收到Entry Move信号,subscription 点位:{} 订阅到消息:{}", nodeName, value.getValue().toString());
readEntryMove();
} else if (nodeName.contains(exitCutIds.get("trigger"))) {
log.info("接收到Exit Cut信号,subscription 点位:{} 订阅到消息:{}", nodeName, value.getValue().toString());
readExitCut();
} else if (nodeName.contains(exitMoveIds.get("trigger"))) {
log.info("接收到Exit Move信号,subscription 点位:{} 订阅到消息:{}", nodeName, value.getValue().toString());
readExitMove();
} else if (nodeName.contains(exitMeasureIds.get("trigger"))) {
log.info("接收到Weight Measure信号,subscription 点位:{} 订阅到消息:{}", nodeName, value.getValue().toString());
readExitMeasure();
} else {
log.info("error ids,subscription 点位:{} 订阅到消息:{}", nodeName, value.getValue().toString());
}
});
} catch (Exception e) {
log.error("EntryMove 订阅失败:{0}",e.getMessage());
}
}
private void readEntryMove()
{
try {
EntryMovementMessage msg =new EntryMovementMessage();
writeMessage( msg,entryMoveIds);
log.info("接收入口移动信号:从 {} 移动到 {} ", msg.getMaterialPlaceSource(), msg.getMaterialPlaceDestination());
//opcReceiverHandler.onMessageReceived(OpcMessageType.ENTRY_MOVEMENT,msg);
} catch (Exception e) {
}
}
private void readExitCut()
{
try {
ExitCutMessage msg = new ExitCutMessage();
writeMessage( msg,exitCutIds);
log.info("接收到出口剪切信号:剪切类型 {},剪切长度{} ", msg.getCutType().toString(), msg.getCutLength());
// opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_CUT,msg);
} catch (Exception e) {
}
}
private void readExitMove()
{
try {
ExitMovementMessage msg = new ExitMovementMessage();
writeMessage( msg,exitMoveIds);
log.info("接收出口移动信号:从 {} 移动到 {} ", msg.getExSrc(), msg.getExDesc());
// opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_MOVEMENT,msg);
} catch (Exception e) {
}
}
private void readExitMeasure()
{
try {
ExitMeasureMessage msg = new ExitMeasureMessage();
writeMessage(msg,exitMoveIds);
log.info("接收出口称重信号:重量 {} ", msg.getWeight());
// opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_MEASURE,msg);
} catch (Exception e) {
}
}
private void writeMessage(OpcMessage msg,Map<String,String> msgIds) throws Exception {
List<String> ids = new ArrayList<>(msgIds.keySet());
ids.remove("trigger");
List<ReadWriteEntity> nodes = miloService.readFromOpcUa(ids);
nodes.forEach(item->{
String fieldName = msgIds.get(item.getIdentifier());
if (fieldName != null) {
try {
Field field = msg.getClass().getDeclaredField(fieldName);
if (field.getType() == ExitCutTypeEnum.class) {
// 使用枚举类的自定义方法
field.setAccessible(true);
ExitCutTypeEnum enumValue = ExitCutTypeEnum.fromCode((int)item.getValue());
field.set(msg, enumValue);
} else {
// 其他类型正常处理
BeanUtils.setProperty(msg, fieldName, item.getValue());
}
} catch (Exception e) {
log.error("BeanUtils设置属性失败: {}", fieldName, e);
}
}
});
}
}

View File

@@ -0,0 +1,108 @@
package com.fizz.business.comm.OPC;
import com.fizz.business.constants.enums.OpcMessageType;
import com.fizz.business.domain.msg.*;
import com.fizz.business.scheduled.BaseSchedule;
import com.fizz.business.service.hanle.OpcReceiverHandler;
import com.kangaroohy.milo.model.ReadWriteEntity;
import com.kangaroohy.milo.service.MiloService;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Random;
@Slf4j
@Component
@AllArgsConstructor
public class MessageTestSchedule extends BaseSchedule {
@Resource
private OpcReceiverHandler opcReceiverHandler;
public static boolean measureStart = false;
public static boolean measureReStart = false;
public static BigDecimal welderLength1 = BigDecimal.valueOf(0);
public static int payOffReelNumber = 1;
public static BigDecimal celLength = BigDecimal.valueOf(500);
public static BigDecimal maxCelLength = new BigDecimal(5000);
public static BigDecimal welderLength2 = BigDecimal.valueOf(0);
public static BigDecimal welderLength3 = BigDecimal.valueOf(0);
public static BigDecimal welderLength4 = BigDecimal.valueOf(0);
public static BigDecimal cxlLength = BigDecimal.valueOf(1000);
@Scheduled(fixedDelay = 1000)
public void L1L2LineMeasure() {
try {
if(measureReStart){
resetValue();
measureReStart = false;
measureStart = true;
return;
}
if(!measureStart) return;
addValue();
Random rand = new Random();
AppMeasureMessage appMeasureMessage = new AppMeasureMessage();
AppMeasureEntryMessage entryMsg = new AppMeasureEntryMessage();
entryMsg.setStripLocation(welderLength1);
entryMsg.setPayOffReelNumber(payOffReelNumber);
entryMsg.setTensionPorBr1(BigDecimal.valueOf(rand.nextDouble()*100));
entryMsg.setTensionBr1Br2(BigDecimal.valueOf(rand.nextDouble()*100));
entryMsg.setTensionBr2Br3(BigDecimal.valueOf(rand.nextDouble()*100));
entryMsg.setStripSpeed(BigDecimal.valueOf(rand.nextDouble()*300));
entryMsg.setTensionCel(BigDecimal.valueOf(rand.nextDouble()*100));
entryMsg.setCelLength(celLength);
entryMsg.setCelCapacity(celLength.divide(maxCelLength));
AppMeasureFurnaceMessage furMsg = new AppMeasureFurnaceMessage();
furMsg.setStripLocation(welderLength2);
furMsg.setStripSpeed(BigDecimal.valueOf(rand.nextDouble()*100));
AppMeasureCoatMessage coatMsg = new AppMeasureCoatMessage();
coatMsg.setStripLocation(welderLength3);
AppMeasureExitMessage exitMsg = new AppMeasureExitMessage();
exitMsg.setStripLocation(welderLength4);
exitMsg.setCxlLength(cxlLength);
exitMsg.setCxlLength(cxlLength.divide(maxCelLength));
appMeasureMessage.setAppMeasureEntryMessage(entryMsg);
appMeasureMessage.setAppMeasureFurnaceMessage(furMsg);
appMeasureMessage.setAppMeasureCoatMessage(coatMsg);
appMeasureMessage.setAppMeasureExitMessage(exitMsg);
log.info("receive");
// opcReceiverHandler.onMessageReceived(OpcMessageType.APP_MEASURE,appMeasureMessage);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void resetValue(){
welderLength1 = BigDecimal.valueOf(0);
payOffReelNumber = 1;
celLength = BigDecimal.valueOf(500);
welderLength2 = BigDecimal.valueOf(0);
}
private void addValue(){
Random rand = new Random();
double nextLength = rand.nextDouble()*10;
welderLength1.add(BigDecimal.valueOf(nextLength));
welderLength2.add(BigDecimal.valueOf(nextLength));
}
}

View File

@@ -1,8 +1,14 @@
package com.fizz.business.constants.enums;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author chenhao
@@ -10,6 +16,36 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum ExitCutTypeEnum {
WELDER_CUT, SPLIT_CUT
public enum ExitCutTypeEnum implements IEnum<String>{
WELDER_CUT(0), SPLIT_CUT(1);
private final Integer code;
private static final Map<String, ExitCutTypeEnum> MAP = new HashMap<>(5);
static {
for (ExitCutTypeEnum e : ExitCutTypeEnum.values()) {
MAP.put(e.getValue(), e);
}
}
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public static ExitCutTypeEnum getByValue(String value) {
return MAP.get(value);
}
@JsonValue
@Override
public String getValue() {
return this.name();
}
public static ExitCutTypeEnum fromCode(int code) {
for (ExitCutTypeEnum unit : values()) {
if (unit.getCode() == code) {
return unit;
}
}
return null;
}
}

View File

@@ -0,0 +1,76 @@
package com.fizz.business.controller;
import com.fizz.business.constants.enums.OpcMessageType;
import com.fizz.business.domain.msg.EntryMovementMessage;
import com.fizz.business.domain.msg.ExitCutMessage;
import com.fizz.business.domain.msg.ExitMeasureMessage;
import com.fizz.business.domain.msg.ExitMovementMessage;
import com.fizz.business.form.ModSetupResultForm;
import com.fizz.business.service.hanle.OpcReceiverHandler;
import com.fizz.business.vo.ModSetupResultVO;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.domain.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import static com.fizz.business.comm.OPC.MessageTestSchedule.measureReStart;
import static com.fizz.business.comm.OPC.MessageTestSchedule.measureStart;
@RestController
@RequestMapping("/api/msgtest")
@Tag(name ="通讯测试")
@Anonymous
public class MessageTestController {
@Resource
private OpcReceiverHandler opcReceiverHandler;
@PostMapping("/entryMove")
@Operation(summary = "入口移动信号")
public void entryMove(@RequestBody EntryMovementMessage msg) {
opcReceiverHandler.onMessageReceived(OpcMessageType.ENTRY_MOVEMENT,msg);
}
@PostMapping("/exitCut")
@Operation(summary = "出口剪切信号")
public void exitCut(@RequestBody ExitCutMessage msg) {
opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_CUT,msg);
}
@PostMapping("/exitMove")
@Operation(summary = "出口移动信号")
public void exitMove(@RequestBody ExitMovementMessage msg) {
opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_MOVEMENT,msg);
}
@PostMapping("/exitMeasure")
@Operation(summary = "出口称重信号")
public void exitMeasure(@RequestBody ExitMeasureMessage msg) {
opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_MEASURE,msg);
}
@PostMapping("/lineMeasure/start")
@Operation(summary = "测量信号-开始")
public void lineMeasureStart() {
measureStart = true;
}
@PostMapping("/lineMeasure/stop")
@Operation(summary = "测量信号-停止")
public void lineMeasureStop() {
measureStart = false;
}
@PostMapping("/lineMeasure/restart")
@Operation(summary = "测量信号-重置")
public void lineMeasureRestart() {
measureReStart = true;
}
}

View File

@@ -1,12 +1,13 @@
package com.fizz.business.domain.msg;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.*;
@Data
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class EntryMovementMessage extends OpcMessage {
private Integer counter;
private Integer materialPlaceSource;
private Integer materialPlaceDestination;
}

View File

@@ -10,7 +10,7 @@ import java.math.BigDecimal;
@Schema(description = "设定电文")
public class PdiSetup {
@Schema(description = "钢卷号")
private String coilNo;
private String coilId;
@Schema(description = "开卷机号")
private Integer PORFlag;
@@ -62,7 +62,7 @@ public class PdiSetup {
@Schema(description = "炉区张力1")
private BigDecimal tensionFur1;
@Schema(description = "炉区张力2")
private BigDecimal tensionFur3;
private BigDecimal tensionFur2;
@Schema(description = "BR4- BR5 张力")
private BigDecimal tensionBR4BR5;
@Schema(description = "目标锌层重量-上表面")

View File

@@ -1,18 +1,26 @@
package com.fizz.business.service.manager;
import com.fizz.business.constants.enums.OpcMessageType;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
@Component
public class OpcMessageIdsManager {
private static Map<String,String> lineMeasureIds = Maps.newHashMap();
private static Map<String,String> entryMoveIds = Maps.newHashMap();
private static Map<String,String> exitCutIds = Maps.newHashMap();
private static Map<String,String> exitMeasureIds = Maps.newHashMap();
private static Map<String,String> exitMoveIds = Maps.newHashMap();
public static List<String> msgTriggers = Lists.newArrayList();
public static Map<String,String> lineMeasureIds = Maps.newHashMap();
public static Map<String,String> entryMoveIds = Maps.newHashMap();
public static Map<String,String> exitCutIds = Maps.newHashMap();
public static Map<String,String> exitMoveIds = Maps.newHashMap();
public static Map<String,String> exitMeasureIds = Maps.newHashMap();
public static String DEVICE_NAME = "ns=2;s=通道 1.";
@PostConstruct
public static void init() {
@@ -20,24 +28,44 @@ public class OpcMessageIdsManager {
//TODO load from database
loadEntryMoveIds();
loadExitCutIds();
loadExitMeasureIds();
loadExitMoveIds();
loadExitMeasureIds();
loadMsgTriggers();
}
public static void loadEntryMoveIds(){
entryMoveIds.put("ns=2;s=通道 2.LockStautsRead.lockStauts1","materialPlaceSource");
entryMoveIds.put("ns=2;s=通道 2.LockStautsRead.lockStauts1","materialPlaceDestination");
entryMoveIds.put("trigger","PLCLine.EntryMove.counter");
entryMoveIds.put("ns=2;s=通道 1.PLCLine.EntryMove.src","materialPlaceSource");
entryMoveIds.put("ns=2;s=通道 1.PLCLine.EntryMove.des","materialPlaceDestination");
}
public static void loadExitCutIds(){
}
public static void loadExitMeasureIds(){
exitCutIds.put("trigger","PLCLine.ExitCut.counter");
exitCutIds.put("ns=2;s=通道 1.PLCLine.ExitCut.cutType","cutType");
exitCutIds.put("ns=2;s=通道 1.PLCLine.ExitCut.cutLength","cutLength");
exitCutIds.put("ns=2;s=通道 1.PLCLine.ExitCut.outerDiameter","outerDiameter");
exitCutIds.put("ns=2;s=通道 1.PLCLine.ExitCut.leftLength","leftLength");
exitCutIds.put("ns=2;s=通道 1.PLCLine.ExitCut.breakPosition","breakPosition");
}
public static void loadExitMoveIds(){
exitMoveIds.put("trigger","PLCLine.ExitMove.counter");
exitMoveIds.put("ns=2;s=通道 1.PLCLine.ExitMove.src","exSrc");
exitMoveIds.put("ns=2;s=通道 1.PLCLine.ExitMove.des","exDesc");
}
public static void loadExitMeasureIds(){
exitMeasureIds.put("trigger","PLCLine.ExitMeasure.counter");
exitMeasureIds.put("ns=2;s=通道 1.PLCLine.ExitMeasure.weight","weight");
}
public static void loadMsgTriggers(){
msgTriggers.add(DEVICE_NAME+entryMoveIds.get("trigger"));
msgTriggers.add(DEVICE_NAME+exitCutIds.get("trigger"));
msgTriggers.add(DEVICE_NAME+exitMoveIds.get("trigger"));
msgTriggers.add(DEVICE_NAME+exitMeasureIds.get("trigger"));
}
}