Java implements OPC UA disconnection reconnection and data monitoring

Introduction

This article will take the Java language as an example to explain in detail how to realize the technology of disconnection, reconnection and data monitoring in OPC UA communication. First, it analyzes why disconnection reconnection and data monitoring are crucial in OPC UA applications, and the limitations of traditional methods. Subsequently, open-source frameworks and libraries for Java, such as Eclipse Milo and Apache Camel, were introduced to handle connection management and data flow in an elegant and efficient manner. At the same time, combined with actual cases, it demonstrates in detail how to use these technical codes to realize OPC UA disconnection and reconnection and data monitoring, so as to achieve system stability and real-time performance. Whether you are an OPC UA beginner or an experienced developer, this article will provide you with valuable technical guidance to help you achieve efficient and stable OPC UA communication.

Introduce dependencies

First, in the maven project, import the org.eclipse.milo jar package dependency

        <dependency>
            <groupId>org.eclipse.milo</groupId>
            <artifactId>sdk-client</artifactId>
            <version>0.6.7</version>
        </dependency>

The Milo library
org.eclipse.milo is a Java-based open source OPC UA (Open Communications Alliance) implementation. OPC UA is an open standard communication protocol used in the field of industrial automation, which provides interoperable data exchange and device management capabilities.

The org.eclipse.milo project aims to provide a complete OPC UA implementation so that developers can easily create and manage OPC UA servers and clients. It is designed to provide a high degree of scalability and flexibility in terms of performance and functionality.

The project is developed and maintained based on the Eclipse Milo subproject in the Eclipse IoT project. Eclipse Milo provides a series of OPC UA libraries and tools to help developers build OPC UA applications on the Java platform. org.eclipse.milo extends Eclipse Milo, providing more functionality and integration options.

With org.eclipse.milo, developers can easily create OPC UA-based applications, including OPC UA servers and clients. It provides a set of APIs that can handle tasks related to OPC UA communication, such as creating and managing nodes, reading and writing variable values, subscribing and publishing events, etc.

org.eclipse.milo also provides some sample applications and tools to help developers get started and quickly start developing OPC UA applications.

To sum up, org.eclipse.milo is a powerful Java-based OPC UA implementation that provides developers with tools and APIs to build and manage OPC UA applications. It is an open source project and can be customized and extended as needed.

OPC UA disconnect and reconnect

Create a subscription event listener SubscriptionListener to implement the implements UaSubscriptionManager.SubscriptionListener interface, the code is as follows:


import com.tarzan.opcua.util.OpcUaUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscription;
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscriptionManager;
import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;

import java.util.Set;


/**
 * @author tarzan
 */
@Slf4j
public class SubscriptionListener implements UaSubscriptionManager.SubscriptionListener {
    
    


    private Set<String> keys;
    private OpcUaClient client;

    public SubscriptionListener(Set<String> keys, OpcUaClient client) {
    
    
        this.keys = keys;
        this.client=client;
    }

    @Override
    public void onKeepAlive(UaSubscription subscription, DateTime publishTime) {
    
    
        log.info("onKeepAlive");
    }

    @Override
    public void onStatusChanged(UaSubscription subscription, StatusCode status) {
    
    
        log.info("onStatusChanged");
    }

    @Override
    public void onPublishFailure(UaException exception) {
    
    
        log.info("onPublishFailure");
    }

    @Override
    public void onNotificationDataLost(UaSubscription subscription) {
    
    
        log.info("onNotificationDataLost");
    }

    /**
     * 重连时 尝试恢复之前的订阅失败时 会调用此方法
     * @param uaSubscription 订阅
     * @param statusCode 状态
     */
    @Override
    public void onSubscriptionTransferFailed(UaSubscription uaSubscription, StatusCode statusCode) {
    
    
        log.info("恢复订阅失败 需要重新订阅");
        //在回调方法中重新订阅
        OpcUaUtil.handlerNode(keys,client);
    }
}

Among them, keys is the set of points that need to be subscribed to, and client is the OpcUa client. onSubscriptionTransferFailed is triggered when the subscription transfer fails, by calling the OpcUaUtil.handlerNode method to re-subscribe points in batches. The handlerNode method implementation code is as follows:


    /**
     * 处理订阅业务
     *
     * @param keys
     */
    public static void handlerNode(Set<String> keys, OpcUaClient client) {
    
    
        try {
    
    
            //创建订阅
            ManagedSubscription subscription = ManagedSubscription.create(client);
            List<NodeId> nodeIdList = new ArrayList<>();
            for (String key : keys) {
    
    
                nodeIdList.add(new NodeId(2, key));
            }
            //监听
            List<ManagedDataItem> dataItemList = subscription.createDataItems(nodeIdList);
            for (ManagedDataItem managedDataItem : dataItemList) {
    
    
                managedDataItem.addDataValueListener(new MyDataValueListener());
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

Among them, MyDataValueListener is a custom opc ua data value change listener.

data monitoring

Create a MyDataValueListener class and implement the onDataValueReceived method of the ManagedDataItem.DataValueListener interface.


import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.sdk.client.subscriptions.ManagedDataItem;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;

/**
 * @author tarzan
 */
@Slf4j
@AllArgsConstructor
public class MyDataValueListener implements ManagedDataItem.DataValueListener {
    
    


    @Override
    public void onDataValueReceived(ManagedDataItem managedDataItem, DataValue dataValue) {
    
    
        log.info(managedDataItem.getNodeId().getIdentifier().toString() + ":" + dataValue.getValue().getValue());
        //do some something
    }
}

Subscribe to use

Create a batch subscription method, pass in the set of point names to be subscribed and the OpcUaClient client


    /**
     * 批量订阅
     *
     * @param keys 订阅
     * @throws Exception
     */
    public  void subscribeEvent(Set<String> keys,OpcUaClient client) throws Exception {
    
    
        final CountDownLatch eventLatch = new CountDownLatch(1);
        //处理订阅业务
        handlerNode(keys,client);
        //添加订阅监听器,用于处理断线重连后的订阅问题
        client.getSubscriptionManager().addSubscriptionListener(new SubscriptionListener(keys,client));
        //持续监听
        eventLatch.await();
    }

To further encapsulate the method, in the service layer, create a subscription method, the code is as follows:

 public void subscribe(Set<String> keys) throws Exception {
    
    
        OpcUaClient client= OpcUaUtil.createClient(endPointUrl);
        opcUaService.subscribeEvent(keys,client);
  }

Then through the controller interface, call the subscribe method of the service layer, or call it in other business layers. In this way, the functions of subscription disconnection reconnection and subscription point value change monitoring can be realized. The code is relatively simple, and you need to add your own business processing. Please make changes to the original code! Let me add below, the method of OpcUaUtil.createClient to create a client, the code is as follows:


    /**
     * 方法描述: 创建客户端
     *
     * @param endPointUrl
     * @return {@link OpcUaClient}
     * @throws
     */
    public static OpcUaClient createClient(String endPointUrl){
    
    
        return createClient(endPointUrl,null,null);
    }

    /**
     * 方法描述: 创建客户端
     *
     * @param endPointUrl
     * @param username
     * @param password
     * @return {@link OpcUaClient}
     * @throws
     */
    public static OpcUaClient createClient(String endPointUrl,String username,String password){
    
    
        log.info(endPointUrl);
        try {
    
    
            //获取安全策略
            List<EndpointDescription> endpointDescription = DiscoveryClient.getEndpoints(endPointUrl).get();
            //过滤出一个自己需要的安全策略
            EndpointDescription endpoint = endpointDescription.stream()
                    .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
                    .findFirst().orElse(null);
            IdentityProvider identityProvider=new AnonymousProvider();
            if(!StringUtils.isEmpty(username)||!StringUtils.isEmpty(password)){
    
    
                identityProvider=new UsernameProvider(username,password);
            }
            // 设置配置信息
            OpcUaClientConfig config = OpcUaClientConfig.builder()
                    // opc ua 自定义的名称
                    .setApplicationName(LocalizedText.english("plc"))
                    // 地址
                    .setApplicationUri(endPointUrl)
                    // 安全策略等配置
                    .setEndpoint(endpoint)
                    .setIdentityProvider(identityProvider)
                    //等待时间
                    .setRequestTimeout(UInteger.valueOf(5000))
                    .build();
            // 准备连接
            OpcUaClient opcClient =OpcUaClient.create(config);
            //开启连接
            opcClient.connect().get();
            log.info("连接成功。。。success");
            return opcClient;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            log.error("======== opc connection fail ========");
        }
        return null;
    }

epilogue

In the project I did, I used this code to monitor the change of the point value at the beginning, but my requirement here is to output the point value in real time. If you use the method of monitoring the value, it may not be output for a long time, because the point value does not change, and the method of monitoring the event will not be triggered. I changed this to a code implementation that reads multiple point values ​​at a time at a time. Regarding the solution for disconnection and reconnection, because I set up a scheduled task, it will be executed once in 1 second. Add another method to obtain the Opc Ua client on the OpcUaUtil.createClient method. When the createClient method returns null, I will call the method of creating the client again. The code is as follows:

   public  OpcUaClient getClient(){
    
    
        if(client==null){
    
    
            client= OpcUaUtil.createClient(endPointUrl);
        }
        return client;
    }

In the service layer, create a subscription method modification, the code is as follows:

 public void subscribe(Set<String> keys) throws Exception {
    
    
        OpcUaClient client= OpcUaUtil.getClient(endPointUrl);
        opcUaService.subscribeEvent(keys,client);
  }

Guess you like

Origin blog.csdn.net/weixin_40986713/article/details/131529181