org.eclipse.milo
sdk-client
0.2.4
org.eclipse.milo
sdk-server
0.2.4
org.eclipse.milo
stack-client
0.2.4
org.eclipse.milo
stack-server
0.2.4
org.eclipse.milo
sdk-client
0.2.4
@Component
public class OpcUaConfig {
public static UaClient opcLink;
/**
* opc ua 打开连接订阅
* res 是否需要重复连接
* @throws Exception
*/
public void createSubscription(boolean res) {
try {
//等待三秒
Thread.sleep(3 * 1000);
UaClient uaClient = null;
// 连接地址,我这是存在数据库里
//String EndPointUrl = "opc.tcp://ip:端口";
String EndPointUrl = configService.selectConfigByKey("sys.opcUa.url");
//安全策略选择
EndpointDescription[] endpointDescription = UaTcpStackClient.getEndpoints(EndPointUrl).get();
//过滤掉不需要的安全策略,选择一个自己需要的安全策略
EndpointDescription endpoint = Arrays.stream(endpointDescription)
.filter(e -> e.getSecurityPolicyUri().equals(None.getSecurityPolicyUri()))
.findFirst().orElseThrow(() -> new Exception("no desired endpoints returned"));
OpcUaClientConfig config = OpcUaClientConfig.builder()
.setApplicationName(LocalizedText.english("bim")) // opc ua 别名
// .setIdentityProvider(new AnonymousProvider())
// .setIdentityProvider(new UsernameProvider("OPCUser","123456"))
.setApplicationUri(EndPointUrl)// 地址
.setEndpoint(endpoint)// 安全策略等配置
.setRequestTimeout(uint(10000)) //等待时间
.build();
OpcUaClient opcClient = new OpcUaClient(config);// 准备连接\
uaClient = opcClient.connect().get();
opcLink = uaClient;
}catch (Exception e){
if(res){
//重复连接
createSubscription(true);
}else{
System.out.println(e.getMessage());
}
}
}
}
}
@Component
public class DeviceOpenConfigProcess implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(DeviceOpenConfigProcess.class);
@Autowired
public RedisCache redisCache;
/**
* 自定义订阅监听
*/
private class CustomSubscriptionListener implements UaSubscriptionManager.SubscriptionListener {
public void onKeepAlive(UaSubscription subscription, DateTime publishTime) {
System.out.println("opcUa监听:onKeepAlive(连接存活中)");
}
public void onStatusChanged(UaSubscription subscription, StatusCode status) {
System.out.println("opcUa监听:onStatusChanged(连接状态改变)");
}
public void onPublishFailure(UaException exception) {
System.out.println("opcUa监听:onPublishFailure(连接断开)");
//连接断开记录
opcUaConfig.opcuaRecord();
}
public void onNotificationDataLost(UaSubscription subscription) {
System.out.println("opcUa监听:onNotificationDataLost(数据丢失)");
}
/**
* 重连时 尝试恢复之前的订阅失败时 会调用此方法
*
* @param uaSubscription 订阅
* @param statusCode 状态
*/
public void onSubscriptionTransferFailed(UaSubscription uaSubscription, StatusCode statusCode) {
//在回调方法中重新订阅
System.out.println("opcUa监听:正在重新启动订阅");
// 获取OPC UA服务器 --参数true就是是否需要重复连接
opcUaConfig.createSubscription(true);
//重启
run();
}
}
public void run() {
deviceOpenConfig(OpcUaConfig.opcLink);
}
/**
* 批量订阅
*/
public void deviceOpenConfig(UaClient opcClient){
try {
//再创建好订阅对象之后将监听加到 SubscriptionManager 里 ------>监听
opcClient.getSubscriptionManager().addSubscriptionListener(new CustomSubscriptionListener());
//我这里是从redis中获取到的,当然也可以从数据读取,看自己业务需要怎么处理 ----我这里的订阅参数是动态的
//注:OpcUaParameter 是自己自定义的实体
List key = redisCache.getCacheList("deviceOpenConfig");
if (StringUtils.isNotNull(key)) {
//创建发布间隔1000ms的订阅对象
UaSubscription subscription = opcClient.getSubscriptionManager().createSubscription(1000).get();
for (int i = 0; i < key.size(); i++) {
String node = key.get(i).getFieldName();
Integer index = key.get(i).getFieldNameIndex();
//创建订阅的变量
NodeId nodeId = new NodeId(index, node);
ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
//创建监控的参数
MonitoringParameters parameters = new MonitoringParameters(
uint(1 + i), // 为了保证唯一性,否则key值一致
0.0, // sampling interval
null, // filter, null means use default
uint(10), // queue size
true // discard oldest
);
MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId,MonitoringMode.Reporting, parameters);
//创建监控项,并且注册变量值改变时候的回调函数。
List items = subscription.createMonitoredItems(
TimestampsToReturn.Both,
newArrayList(request),
(item, id) -> {
item.setValueConsumer((is, value) -> {
//检测redis是否发生了变化 ---redis更新可以忽略
List lists = redisCache.getCacheList("deviceOpenConfig");
//判断key与lists对象是否相同
Boolean exist = opcUaConfig.exist(key, lists);
if (exist) {
System.out.println("---------deviceOpenConfig缓存数据发生了变化------------");
deviceOpenConfig(opcClient);
}
String nodeName = item.getReadValueId().getNodeId().getIdentifier().toString();
String nodeValue = value.getValue().getValue().toString();
System.out.println("参数:"+nodeName+"-----------值:"+nodeValue);
});
}).get();
}
} else {
LOGGER.info("暂无采集数据");
Thread.sleep(3 * 1000);
//重新执行本方法
deviceOpenConfig(opcClient);
}
} catch (Exception e) {
LOGGER.error("----------参数出现异常----------");
LOGGER.error(e.getMessage());
}
}
}
注:DeviceOpenConfigProcess implements Runnable 是因为我们的业务线不只是单单只有这一个批量订阅,如果你的业务只是单业务线批量订阅可以在服务启动成功后进行执行。以上就是我目前所处理方法,第一次接触,本人知识有限,如果还有更好的方法或者有什么不对的可以提出。