JAVA与PLC通信:OPCUA - 基于Milo

shunzaa

发布于 2022.10.03 19:09 阅读 1423 评论 0

   本文记录JAVA使用Milo与PLC进行连接(PLC开启OPCUA),Milo有一个订阅的功能,订阅一个地址后,当地址中的数据发生变化的时候会主动通知,接下来记录一下Milo的用法:

1. 创建连接

 public OpcUaClient createClient() {
        if(opcUaClient != null){
            return opcUaClient;
        }

        Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
        try {
            Files.createDirectories(securityTempDir);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        if (!Files.exists(securityTempDir)) {
            try {
                throw new Exception("不能够创建安全路径: " + securityTempDir);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
//        KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir);
        // 获取OPC UA的服务器端节点,OPCUA有多种加密方法(可在PLC中设置),当前只列出了不使用任何加密的方式进行连接,其他方式的连接会在以后进行补充
        //applicationUri 可在PLC中查询到,applicationName为uri冒号后面的内容;
        EndpointDescription[] endpoints =
                new EndpointDescription[0];
        try {
            endpoints = UaTcpStackClient.getEndpoints(endpointUrl).get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        EndpointDescription endpoint = null;
        try {
            endpoint = Arrays.stream(endpoints)
                    .filter(e -> e.getEndpointUrl().equals(endpointUrl))
                    .findFirst().orElseThrow(() -> new Exception("没有节点返回"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // 设置OPC UA的配置信息
        OpcUaClientConfig config =
                OpcUaClientConfig.builder()
//                        .setApplicationName(LocalizedText.english("PLC_NAME"))
                        .setApplicationName(LocalizedText.english("KEPServerEX/UA Server")) //此处填Uri中冒号后面的字符串
//                        .setApplicationUri("urn:SIMATIC.S7-1500.OPC-UA.Application:PLC_APPNAME")
                        .setApplicationUri("urn:wang-PC:KEPServerEX/UA Server") //PLC连接信息
//                        .setCertificate(loader.getClientCertificate())
//                        .setKeyPair(loader.getClientKeyPair())
                        .setEndpoint(endpoint)
                        .setIdentityProvider(new AnonymousProvider())
                        .setRequestTimeout(uint(5000))
                        .build();
        // 创建OPC UA客户端
        opcUaClient = new OpcUaClient(config);
        return opcUaClient;
    }

2. 订阅节点

节点名称:

Channel1.Device1.TAG1

枚举:

public class OpcNodeList {
    public static String LINE_CYLINDER_SCAN ="Channel1.Device1.TAG1";
}

订阅节点: 

  public void createSubscription() {
        OpcUaClient client = null;
        try {
            client = createClient();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //创建连接
        try {
            client.connect().get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        //创建发布间隔1000ms的订阅对象
        UaSubscription subscription = null;
        try {
            subscription = client.getSubscriptionManager().createSubscription(1000.0).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        //创建监控的参数
        MonitoringParameters parameters1 = new MonitoringParameters(
                uint(1),
                1000.0,     // sampling interval
                null,       // filter, null means use default
                uint(10),   // queue size
                true        // discard oldest
        );


        //创建订阅
        NodeId nodeId1 = new NodeId(2, OpcNodeList.LINE_CYLINDER_SCAN);
        ReadValueId readValueId1 = new ReadValueId(nodeId1, AttributeId.Value.uid(),null,null);
        //该请求最后用于创建订阅。
        MonitoredItemCreateRequest request1 = new MonitoredItemCreateRequest(readValueId1, MonitoringMode.Reporting, parameters1);

        List<MonitoredItemCreateRequest> requests = new ArrayList<>();
        requests.add(request1);

        //创建监控项,并且注册变量值改变时候的回调函数。
        try {
            List<UaMonitoredItem> items = subscription.createMonitoredItems(
                    TimestampsToReturn.Both,
                    requests,
                    (item,id)->{
                        item.setValueConsumer((itemC, value)->{
                            System.out.println("id :"+id);
                            System.out.println("nodeid :"+itemC.getReadValueId().getNodeId());
                            System.out.println("value :"+value.getValue().getValue());
                            //todo 此处监听回调的地址以及数据


                        });
                    }
            ).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

3. 源码地址

    https://gitee.com/kingrisingsun/opcuamilo-demo