feat():OPC UA环境
This commit is contained in:
@@ -47,12 +47,12 @@
|
||||
<artifactId>ruoyi-framework</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 加密解密工具-->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.70</version>
|
||||
</dependency>
|
||||
<!-- 加密解密工具 opc-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.bouncycastle</groupId>-->
|
||||
<!-- <artifactId>bcprov-jdk15on</artifactId>-->
|
||||
<!-- <version>1.70</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -108,6 +108,14 @@
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- OPC UA 集成 -->
|
||||
<dependency>
|
||||
<groupId>com.kangaroohy</groupId>
|
||||
<artifactId>milo-spring-boot-starter</artifactId>
|
||||
<version>3.1.4.0.6.15</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.alibaba</groupId>-->
|
||||
<!-- <artifactId>fastjson</artifactId>-->
|
||||
|
||||
@@ -36,14 +36,14 @@ public class AppMeasureEntryMessage extends OpcMessage {
|
||||
@Schema(description = "钢带速度 (m/min)")
|
||||
private BigDecimal stripSpeed;
|
||||
|
||||
@Schema(description = "入口活套位置最大值 (m)")
|
||||
private BigDecimal entryLooperPositionMax;
|
||||
@Schema(description = "入口活套位置(m)")
|
||||
private BigDecimal celLength;
|
||||
|
||||
@Schema(description = "入口活套位置最小值 (m)")
|
||||
private BigDecimal entryLooperPositionMin;
|
||||
@Schema(description = "入口活套百分比(m)")
|
||||
private BigDecimal celCapacity;
|
||||
|
||||
@Schema(description = "当前实际活套位置 (m)")
|
||||
private BigDecimal entryLooperPositionCurrent;
|
||||
@Schema(description = "入口活套张力(m)")
|
||||
private BigDecimal tensionCel ;
|
||||
|
||||
@Schema(description = "清洗电压 (V)")
|
||||
private BigDecimal cleaningVoltage;
|
||||
|
||||
@@ -21,17 +21,14 @@ public class AppMeasureExitMessage extends OpcMessage {
|
||||
@Schema(description = "钢带张力 BR8 – BR9 (daN)")
|
||||
private BigDecimal tensionBr8Br9;
|
||||
|
||||
@Schema(description = "出口活套位置 (m)")
|
||||
private BigDecimal deliveryLooperPosition;
|
||||
@Schema(description = "入口活套位置(m)")
|
||||
private BigDecimal cxlLength;
|
||||
|
||||
@Schema(description = "出口活套最大可用百分比 (%)")
|
||||
private BigDecimal exitLooperMaxPercent;
|
||||
@Schema(description = "入口活套百分比(m)")
|
||||
private BigDecimal cxlCapacity;
|
||||
|
||||
@Schema(description = "出口活套最小可用百分比 (%)")
|
||||
private BigDecimal exitLooperMinPercent;
|
||||
|
||||
@Schema(description = "出口活套当前百分比 (%)")
|
||||
private BigDecimal exitLooperCurrentPercent;
|
||||
@Schema(description = "入口活套张力(m)")
|
||||
private BigDecimal tensionCxl ;
|
||||
|
||||
@Schema(description = "涂油标志 (0=no, 1=yes)")
|
||||
private Integer oilingFlag;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
11111
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.fizz.business.scheduled;
|
||||
|
||||
import com.fizz.business.utils.RedisLockUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Slf4j
|
||||
@Async("threadPoolTaskExecutor")
|
||||
@Component
|
||||
@EnableScheduling
|
||||
public abstract class BaseSchedule {
|
||||
|
||||
/**
|
||||
* 默认key过期时间 1800秒
|
||||
*/
|
||||
private static final int DEFAULT_EXPIRE_SECONDS = 1800;
|
||||
|
||||
protected void execute(String taskName, int cacheSeconds, String cacheKey, Runnable func) {
|
||||
// 执行完2分钟 删除键值
|
||||
int delayedSeconds = Math.min(120, cacheSeconds / 10);
|
||||
execute(taskName, cacheSeconds, delayedSeconds, cacheKey, k -> func.run());
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务执行 多服务防止同时执行
|
||||
*
|
||||
* @param taskName: 任务名称
|
||||
* @param cacheSeconds: <= 0时默认时间
|
||||
* @param delayedSeconds: 任务执行完延时删除key; <0时默认 cacheSeconds/10
|
||||
* @param cacheKey:
|
||||
* @param func: 执行的任务 key: 处理后的cacheKey
|
||||
*/
|
||||
protected void execute(String taskName, int cacheSeconds, int delayedSeconds, String cacheKey, Consumer<String> func) {
|
||||
String threadName = Thread.currentThread().getName();
|
||||
cacheKey = "scheduling:" + cacheKey;
|
||||
if (cacheSeconds <= 0) {
|
||||
cacheSeconds = DEFAULT_EXPIRE_SECONDS;
|
||||
}
|
||||
if (delayedSeconds < 0) {
|
||||
delayedSeconds = cacheSeconds / 10;
|
||||
}
|
||||
// 不存在键值时执行
|
||||
String value = "1";
|
||||
boolean success = RedisLockUtil.setIfAbsent(cacheKey, value, cacheSeconds);
|
||||
if (!success) {
|
||||
log.debug("定时任务: {}, 取消执行. {}", taskName, threadName);
|
||||
return;
|
||||
}
|
||||
log.debug("定时任务: {}, 开始执行. {}", taskName, threadName);
|
||||
func.accept(cacheKey);
|
||||
// 执行完后 延时时间内不可重复执行
|
||||
if (delayedSeconds == 0) {
|
||||
RedisLockUtil.delLock(cacheKey, value);
|
||||
} else {
|
||||
RedisLockUtil.setIfPresent(cacheKey, value, delayedSeconds);
|
||||
}
|
||||
log.debug("定时任务: {}, 执行结束. {}", taskName, threadName);
|
||||
}
|
||||
|
||||
public void actionCatchException(Runnable func) {
|
||||
String threadName = Thread.currentThread().getName();
|
||||
try {
|
||||
func.run();
|
||||
} catch (Exception e) {
|
||||
log.error("定时任务执行出错 " + threadName, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.fizz.business.scheduled;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.kangaroohy.milo.model.ReadWriteEntity;
|
||||
import com.kangaroohy.milo.service.MiloService;
|
||||
import jdk.nashorn.internal.runtime.Debug;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
//@Component
|
||||
@AllArgsConstructor
|
||||
public class LineMeasureSchedule extends BaseSchedule{
|
||||
|
||||
@Resource
|
||||
MiloService miloService;
|
||||
@Scheduled(fixedDelay = 200)
|
||||
public void L1L2LineMeasure() {
|
||||
try {
|
||||
ReadWriteEntity node = miloService.readFromOpcUa("ns=2;s=通道 2.LockStautsRead.lockStauts1");
|
||||
log.debug(node.toString());
|
||||
node.getValue();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.fizz.business.utils;
|
||||
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Component
|
||||
public class RedisLockUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(RedisLockUtil.class);
|
||||
public static final RedisScript<Long> UNLOCK_SCRIPT = new DefaultRedisScript("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", Long.class);
|
||||
private static final String UNLOCK_LUA = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||
private static RedisTemplate<String, String> REDIS_TEMPLATE;
|
||||
|
||||
@Autowired
|
||||
public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
|
||||
REDIS_TEMPLATE = redisTemplate;
|
||||
}
|
||||
|
||||
private RedisLockUtil() {
|
||||
}
|
||||
|
||||
public static boolean setIfAbsent(@NotNull String key, @NotNull String value, int seconds) {
|
||||
Boolean result = REDIS_TEMPLATE.opsForValue().setIfAbsent(key, value, (long)seconds, TimeUnit.SECONDS);
|
||||
return result != null && result;
|
||||
}
|
||||
|
||||
public static boolean setIfPresent(@NotNull String key, @NotNull String value, int seconds) {
|
||||
Boolean result = REDIS_TEMPLATE.opsForValue().setIfPresent(key, value, (long)seconds, TimeUnit.SECONDS);
|
||||
return result != null && result;
|
||||
}
|
||||
|
||||
public static void delLock(@NotNull String key, @NotNull String value) {
|
||||
REDIS_TEMPLATE.execute(UNLOCK_SCRIPT, Collections.singletonList(key), new Object[]{value});
|
||||
}
|
||||
|
||||
public static <V> Pair<Boolean, V> lockHandle(@NotNull String key, @NotNull Callable<V> callable, @NotNull Function<Exception, Pair<Boolean, V>> exceptionHandle) {
|
||||
String threadName = Thread.currentThread().getName();
|
||||
String msg = "RedisLockUtil " + threadName + " {}:" + key;
|
||||
String value = IdUtil.simpleUUID();
|
||||
boolean success = setIfAbsent(key, value, 6000);
|
||||
if (!success) {
|
||||
log.debug(msg, "锁获取失败");
|
||||
return new Pair(false, (Object)null);
|
||||
} else {
|
||||
log.debug(msg, "锁获取成功");
|
||||
|
||||
Pair var8;
|
||||
try {
|
||||
V v = callable.call();
|
||||
log.debug(msg, "执行完成");
|
||||
var8 = new Pair(true, v);
|
||||
return var8;
|
||||
} catch (Exception var12) {
|
||||
log.error(StrUtil.format(msg, new Object[]{"成功获取锁但执行失败"}), var12);
|
||||
var8 = (Pair)exceptionHandle.apply(var12);
|
||||
} finally {
|
||||
delLock(key, value);
|
||||
}
|
||||
|
||||
return var8;
|
||||
}
|
||||
}
|
||||
|
||||
public static <V> Pair<Boolean, V> lockHandle(@NotNull String key, @NotNull Callable<V> callable) {
|
||||
return lockHandle(key, callable, (e) -> {
|
||||
throw new RuntimeException(key + " 成功获取锁但执行失败:" + e.getMessage());
|
||||
});
|
||||
}
|
||||
}
|
||||
9
pom.xml
9
pom.xml
@@ -34,6 +34,9 @@
|
||||
<knife4j.version>4.5.0</knife4j.version>
|
||||
<springdoc.version>1.7.0</springdoc.version>
|
||||
<mybatis.version>3.5.2</mybatis.version>
|
||||
<milo.version>0.6.3</milo.version>
|
||||
<commons-pool2.version>2.12.0</commons-pool2.version>
|
||||
<!-- 2.12.0-->
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
@@ -212,6 +215,12 @@
|
||||
<!-- <version>3.5.2</version>-->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
<version>${commons-pool2.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -101,6 +101,10 @@ spring:
|
||||
enabled: true
|
||||
max-attempts: 1
|
||||
max-interval: 200
|
||||
task:
|
||||
scheduling:
|
||||
pool:
|
||||
size: 8 #配置Scheduled定时任务为多线程
|
||||
|
||||
# token配置
|
||||
token:
|
||||
@@ -160,4 +164,33 @@ knife4j:
|
||||
language: zh-CN # 中文界面
|
||||
enable-swagger-model: true # 显示模型
|
||||
enable-document-manage: true # 启用文档管理
|
||||
cors: true # 允许跨域
|
||||
cors: true # 允许跨域
|
||||
|
||||
kangaroohy:
|
||||
milo:
|
||||
primary: default
|
||||
config:
|
||||
default:
|
||||
endpoint: opc.tcp://127.0.0.1:49320
|
||||
security-policy: none
|
||||
pool:
|
||||
max-idle: 5
|
||||
max-total: 20
|
||||
min-idle: 2
|
||||
initial-size: 3
|
||||
|
||||
|
||||
#kangaroohy:
|
||||
# milo:
|
||||
# primary: default
|
||||
# config:
|
||||
# default:
|
||||
# endpoint: opc.tcp://127.0.0.1:49320
|
||||
# security-policy: basic256sha256
|
||||
# username: OPCUA
|
||||
# password: 123456
|
||||
# test:
|
||||
# endpoint: opc.tcp://127.0.0.1:49321
|
||||
# security-policy: basic256sha256
|
||||
# username: OPCUA
|
||||
# password: 123456
|
||||
@@ -149,8 +149,6 @@
|
||||
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.swagger</groupId>-->
|
||||
|
||||
Reference in New Issue
Block a user