国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringBoot集成Milo庫實現(xiàn)OPC UA客戶端:連接、遍歷節(jié)點、讀取、寫入、訂閱與批量訂閱

這篇具有很好參考價值的文章主要介紹了SpringBoot集成Milo庫實現(xiàn)OPC UA客戶端:連接、遍歷節(jié)點、讀取、寫入、訂閱與批量訂閱。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

背景

前面我們搭建了一個本地的 PLC 仿真環(huán)境,并通過 KEPServerEX6 讀取 PLC 上的數(shù)據(jù),最后還使用 UAExpert 作為OPC客戶端完成從 KEPServerEX6 這個OPC服務器的數(shù)據(jù)讀取與訂閱功能。在這篇文章中,我們將通過 SpringBoot 集成 Milo 庫實現(xiàn)一個 OPC UA 客戶端,包括連接、遍歷節(jié)點、讀取、寫入、訂閱與批量訂閱等功能。

Milo庫

Milo 庫的 GitHub 地址:https://github.com/eclipse/milo

Milo 庫提供了 OPC UA 的服務端和客戶端 SDK ,顯然,我們這里僅用到了OPC UA Client SDK

引入依賴

SpringBoot 后端項目中引入 Milo 庫依賴(客戶端 SDK )。

實現(xiàn)OPCUA客戶端

連接

    /**
     * 創(chuàng)建OPC UA客戶端
     *
     * @param ip
     * @param port
     * @param suffix
     * @return
     * @throws Exception
     */
    public OpcUaClient connectOpcUaServer(String ip, String port, String suffix) throws Exception {
        String endPointUrl = "opc.tcp://" + ip + ":" + port + suffix;
        Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
        Files.createDirectories(securityTempDir);
        if (!Files.exists(securityTempDir)) {
            throw new Exception("unable to create security dir: " + securityTempDir);
        }
        OpcUaClient opcUaClient = OpcUaClient.create(endPointUrl,
                endpoints ->
                        endpoints.stream()
                                .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
                                .findFirst(),
                configBuilder ->
                        configBuilder
                                .setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
                                .setApplicationUri("urn:eclipse:milo:examples:client")
                                //訪問方式
                                .setIdentityProvider(new AnonymousProvider())
                                .setRequestTimeout(UInteger.valueOf(5000))
                                .build()
        );
        opcUaClient.connect().get();
        Thread.sleep(2000); // 線程休眠一下再返回對象,給創(chuàng)建過程一個時間。
        return opcUaClient;
    }

遍歷節(jié)點

    /**
     * 遍歷樹形節(jié)點
     *
     * @param client OPC UA客戶端
     * @param uaNode 節(jié)點
     * @throws Exception
     */
    public void listNode(OpcUaClient client, UaNode uaNode) throws Exception {
        List<? extends UaNode> nodes;
        if (uaNode == null) {
            nodes = client.getAddressSpace().browseNodes(Identifiers.ObjectsFolder);
        } else {
            nodes = client.getAddressSpace().browseNodes(uaNode);
        }
        for (UaNode nd : nodes) {
            //排除系統(tǒng)性節(jié)點,這些系統(tǒng)性節(jié)點名稱一般都是以"_"開頭
            if (Objects.requireNonNull(nd.getBrowseName().getName()).contains("_")) {
                continue;
            }
            System.out.println("Node= " + nd.getBrowseName().getName());
            listNode(client, nd);
        }
    }

讀取指定節(jié)點

    /**
     * 讀取節(jié)點數(shù)據(jù)
     *
     * namespaceIndex可以通過UaExpert客戶端去查詢,一般來說這個值是2。
     * identifier也可以通過UaExpert客戶端去查詢,這個值=通道名稱.設備名稱.標記名稱
     *
     * @param client
     * @param namespaceIndex
     * @param identifier
     * @throws Exception
     */
    public void readNodeValue(OpcUaClient client, int namespaceIndex, String identifier) throws Exception {
        //節(jié)點
        NodeId nodeId = new NodeId(namespaceIndex, identifier);

        //讀取節(jié)點數(shù)據(jù)
        DataValue value = client.readValue(0.0, TimestampsToReturn.Neither, nodeId).get();

        // 狀態(tài)
        System.out.println("Status: " + value.getStatusCode());

        //標識符
        String id = String.valueOf(nodeId.getIdentifier());
        System.out.println(id + ": " + value.getValue().getValue());
    }

寫入指定節(jié)點

    /**
     * 寫入節(jié)點數(shù)據(jù)
     *
     * @param client
     * @param namespaceIndex
     * @param identifier
     * @param value
     * @throws Exception
     */
    public void writeNodeValue(OpcUaClient client, int namespaceIndex, String identifier, Float value) throws Exception {
        //節(jié)點
        NodeId nodeId = new NodeId(namespaceIndex, identifier);
        //創(chuàng)建數(shù)據(jù)對象,此處的數(shù)據(jù)對象一定要定義類型,不然會出現(xiàn)類型錯誤,導致無法寫入
        DataValue newValue = new DataValue(new Variant(value), null, null);
        //寫入節(jié)點數(shù)據(jù)
        StatusCode statusCode = client.writeValue(nodeId, newValue).join();
        System.out.println("結果:" + statusCode.isGood());
    }

訂閱指定節(jié)點

    /**
     * 訂閱(單個)
     *
     * @param client
     * @param namespaceIndex
     * @param identifier
     * @throws Exception
     */
    private static final AtomicInteger atomic = new AtomicInteger();

    public void subscribe(OpcUaClient client, int namespaceIndex, String identifier) throws Exception {
        //創(chuàng)建發(fā)布間隔1000ms的訂閱對象
        client
                .getSubscriptionManager()
                .createSubscription(1000.0)
                .thenAccept(t -> {
                    //節(jié)點
                    NodeId nodeId = new NodeId(namespaceIndex, identifier);
                    ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
                    //創(chuàng)建監(jiān)控的參數(shù)
                    MonitoringParameters parameters = new MonitoringParameters(UInteger.valueOf(atomic.getAndIncrement()), 1000.0, null, UInteger.valueOf(10), true);
                    //創(chuàng)建監(jiān)控項請求
                    //該請求最后用于創(chuàng)建訂閱。
                    MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);
                    List<MonitoredItemCreateRequest> requests = new ArrayList<>();
                    requests.add(request);
                    //創(chuàng)建監(jiān)控項,并且注冊變量值改變時候的回調函數(shù)。
                    t.createMonitoredItems(
                            TimestampsToReturn.Both,
                            requests,
                            (item, id) -> item.setValueConsumer((it, val) -> {
                                System.out.println("nodeid :" + it.getReadValueId().getNodeId());
                                System.out.println("value :" + val.getValue().getValue());
                            })
                    );
                }).get();

        //持續(xù)訂閱
        Thread.sleep(Long.MAX_VALUE);
    }

批量訂閱指定節(jié)點

    /**
     * 批量訂閱
     *
     * @param client
     * @throws Exception
     */
    public void subscribeBatch(OpcUaClient client) throws Exception {
        final CountDownLatch eventLatch = new CountDownLatch(1);
        //處理訂閱業(yè)務
        handlerMultipleNode(client);
        //持續(xù)監(jiān)聽
        eventLatch.await();
    }

    /**
     * 處理訂閱業(yè)務
     *
     * @param client OPC UA客戶端
     */
    private void handlerMultipleNode(OpcUaClient client) {
        try {
            //創(chuàng)建訂閱
            ManagedSubscription subscription = ManagedSubscription.create(client);
            List<NodeId> nodeIdList = new ArrayList<>();
            for (String id : batchIdentifiers) {
                nodeIdList.add(new NodeId(batchNamespaceIndex, id));
            }
            //監(jiān)聽
            List<ManagedDataItem> dataItemList = subscription.createDataItems(nodeIdList);
            for (ManagedDataItem managedDataItem : dataItemList) {
                managedDataItem.addDataValueListener((t) -> {
                    System.out.println(managedDataItem.getNodeId().getIdentifier().toString() + ":" + t.getValue().getValue().toString());
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

關于斷線重連的批量訂閱,可以參考文末源碼,我沒有進行實際測試。

測試

連接KEPServerEX6的OPC UA服務器

將上一篇文章中的 KEPServerEX6 作為 OPC UA 服務器來測試我們實現(xiàn)的客戶端功能。這里 namespaceIndexidentifier 參考 KEPServerEX6 的配置或者 UAExpert 的右上角 Attribute 顯示。

SpringBoot集成Milo庫實現(xiàn)OPC UA客戶端:連接、遍歷節(jié)點、讀取、寫入、訂閱與批量訂閱

public class OpcUaStart {
    public void start() throws Exception {
        OpcUaClientService opcUaClientService = new OpcUaClientService();

        // 與OPC UA服務端建立連接,并返回客戶端實例
        OpcUaClient client = opcUaClientService.connectOpcUaServer("127.0.0.1", "49320", "");

        // 遍歷所有節(jié)點
        opcUaClientService.listNode(client, null);

        // 讀取指定節(jié)點的值
//        opcUaClientService.readNodeValue(client, 2, "Demo.1500PLC.D1");
//        opcUaClientService.readNodeValue(client, 2, "Demo.1500PLC.D2");

        // 向指定節(jié)點寫入數(shù)據(jù)
        opcUaClientService.writeNodeValue(client, 2, "Demo.1500PLC.D1", 6f);

        // 訂閱指定節(jié)點
//        opcUaClientService.subscribe(client, 2, "Demo.1500PLC.D1");

        // 批量訂閱多個節(jié)點
        List<String> identifiers = new ArrayList<>();
        identifiers.add("Demo.1500PLC.D1");
        identifiers.add("Demo.1500PLC.D2");

        opcUaClientService.setBatchNamespaceIndex(2);
        opcUaClientService.setBatchIdentifiers(identifiers);

//        opcUaClientService.subscribeBatch(client);
        opcUaClientService.subscribeBatchWithReconnect(client);
    }
}

記得在啟動類中開啟 OPC UA 的客戶端。

@SpringBootApplication
public class SpringbootOpcuaApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringbootOpcuaApplication.class, args);
        OpcUaStart opcUa = new OpcUaStart();
        opcUa.start();
    }
}

連接Milo提供的測試性OPC UA服務器

Milo 官方提供了一個開放的 OPC UA 服務器: opc.tcp://milo.digitalpetri.com:62541/milo ,可以先使用 UAExpert 測試連接(我用的是匿名連接),查看其中的節(jié)點及地址信息。

SpringBoot集成Milo庫實現(xiàn)OPC UA客戶端:連接、遍歷節(jié)點、讀取、寫入、訂閱與批量訂閱

public class OpcUaStart {
    public void start() throws Exception {
        OpcUaClientService opcUaClientService = new OpcUaClientService();

        // 與OPC UA服務端建立連接,并返回客戶端實例
        OpcUaClient client = opcUaClientService.connectOpcUaServer("milo.digitalpetri.com", "62541", "/milo");

        // 遍歷所有節(jié)點
//        opcUaClientService.listNode(client, null);

        // 讀取指定節(jié)點的值
        opcUaClientService.readNodeValue(client, 2, "Dynamic/RandomInt32");
        opcUaClientService.readNodeValue(client, 2, "Dynamic/RandomInt64");

        // 向指定節(jié)點寫入數(shù)據(jù)
//        opcUaClientService.writeNodeValue(client, 2, "Demo.1500PLC.D1", 6f);

        // 訂閱指定節(jié)點
//        opcUaClientService.subscribe(client, 2, "Dynamic/RandomDouble");

        // 批量訂閱多個節(jié)點
        List<String> identifiers = new ArrayList<>();
        identifiers.add("Dynamic/RandomDouble");
        identifiers.add("Dynamic/RandomFloat");

        opcUaClientService.setBatchNamespaceIndex(2);
        opcUaClientService.setBatchIdentifiers(identifiers);

//        opcUaClientService.subscribeBatch(client);
        opcUaClientService.subscribeBatchWithReconnect(client);
    }
}

測試結果如下:
SpringBoot集成Milo庫實現(xiàn)OPC UA客戶端:連接、遍歷節(jié)點、讀取、寫入、訂閱與批量訂閱

可能遇到的問題

UaException: status=Bad_SessionClosed, message=The session was closed by the client.

原因分析: opcUaClient.connect().get(); 是一個異步的過程,可能在讀寫的時候,連接還沒有創(chuàng)建好。

解決方法: Thread.sleep(2000); // 線程休眠一下再返回對象,給創(chuàng)建過程一個時間。

Reference

https://blog.csdn.net/u013457145/article/details/121283612

Source Code

https://github.com/heartsuit/demo-spring-boot/tree/master/springboot-opcua


If you have any questions or any bugs are found, please feel free to contact me.

Your comments and suggestions are welcome!文章來源地址http://www.zghlxwxcb.cn/news/detail-483626.html

到了這里,關于SpringBoot集成Milo庫實現(xiàn)OPC UA客戶端:連接、遍歷節(jié)點、讀取、寫入、訂閱與批量訂閱的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【OPC UA】C# 通過OpcUaHelper建立OPC客戶端訪問KEPServerEx6 OPC服務器數(shù)據(jù)

    【OPC UA】C# 通過OpcUaHelper建立OPC客戶端訪問KEPServerEx6 OPC服務器數(shù)據(jù)

    OpcUaHelper 一個通用的opc ua客戶端類庫,基于.net 4.6.1創(chuàng)建,基于官方opc ua基金會跨平臺庫創(chuàng)建,封裝了節(jié)點讀寫,批量節(jié)點讀寫,引用讀取,特性讀取,歷史數(shù)據(jù)讀取,方法調用,節(jié)點訂閱,批量訂閱等操作。還提供了一個節(jié)點瀏覽器工具。 KEPServerEX 第三方的OPC服務器,各不

    2023年04月11日
    瀏覽(18)
  • 二、springboot集成CAS客戶端實現(xiàn)單點登錄

    pom中引入依賴 yml中添加cas配置 讀取CAS相關配置 cas配置類 單點登錄接口demo 訪問loingCas接口時,若未在CASserver登錄,則會被攔截跳轉到CAS的登陸頁面,登陸成功后放行繼續(xù)訪問loginCas接口

    2024年02月15日
    瀏覽(23)
  • SpringBoot集成WebSocket實現(xiàn)客戶端與服務端通信

    SpringBoot集成WebSocket實現(xiàn)客戶端與服務端通信

    話不多說,直接上代碼看效果! 一、服務端: 1、引用依賴 2、添加配置文件 WebSocketConfig 3、編寫WebSocket服務端接收、發(fā)送功能 ? 聲明接口代碼: ? 實現(xiàn)類代碼: 4、如果不需要實現(xiàn)客戶端功能,此處可選擇前端調用,奉上代碼 二、客戶端: 1、引用依賴 2、自定義WebSocket客

    2024年01月23日
    瀏覽(24)
  • SpringBoot集成WebSocket實現(xiàn)客戶端與服務端長連接通信

    SpringBoot集成WebSocket實現(xiàn)客戶端與服務端長連接通信

    場景: 1、WebSocket協(xié)議是用于前后端長連接交互的技術,此技術多用于交互不斷開的場景。特點是連接不間斷、更輕量,只有在關閉瀏覽器窗口、或者關閉瀏覽器、或主動close,當前會話對象才會關閉。 2、相較于 Http/Https?通信只能由客戶端主動發(fā)起請求,而 Socket?通信不僅能

    2024年02月02日
    瀏覽(28)
  • springboot集成webstock實戰(zhàn):服務端數(shù)據(jù)推送數(shù)據(jù)到客戶端實現(xiàn)實時刷新

    springboot集成webstock實戰(zhàn):服務端數(shù)據(jù)推送數(shù)據(jù)到客戶端實現(xiàn)實時刷新

    ????之前介紹過springboot集成webstock方式,具體參考: springboot集成websocket實戰(zhàn):站內消息實時推送 這里補充另外一個使用webstock的場景,方便其他同學理解和使用,廢話不多說了,直接開始!簡單介紹一下業(yè)務場景: ????現(xiàn)在有一個投票活動,活動詳情中會顯示投票活動的參與人數(shù)、訪

    2024年02月08日
    瀏覽(48)
  • Forest-聲明式HTTP客戶端框架-集成到SpringBoot實現(xiàn)調用第三方restful api并實現(xiàn)接口數(shù)據(jù)轉換

    Forest-聲明式HTTP客戶端框架-集成到SpringBoot實現(xiàn)調用第三方restful api并實現(xiàn)接口數(shù)據(jù)轉換

    聲明式HTTP客戶端API框架,讓Java發(fā)送HTTP/HTTPS請求不再難。它比OkHttp和HttpClient更高層, 是封裝調用第三方restful api client接口的好幫手,是retrofit和feign之外另一個選擇。 通過在接口上聲明注解的方式配置HTTP請求接口。 官網(wǎng): Forest ? 代碼地址: forest: 聲明式HTTP客戶端API框架,讓

    2024年02月04日
    瀏覽(25)
  • kafka:java集成 kafka(springboot集成、客戶端集成)

    kafka:java集成 kafka(springboot集成、客戶端集成)

    摘要 對于java的kafka集成,一般選用springboot集成kafka,但可能由于對接方kafka老舊、kafka不安全等問題導致kafak版本與spring版本不兼容,這個時候就得自己根據(jù)kafka客戶端api集成了。 一、springboot集成kafka 具體官方文檔地址:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/

    2023年04月22日
    瀏覽(92)
  • SpringBoot2.0集成WebSocket,多客戶端

    適用于單客戶端,一個賬號登陸一個客戶端,登陸多個客戶端會報錯 The remote endpoint was in state [TEXT_FULL_WRITING]? 這是因為此時的session是不同的,只能鎖住一個session,解決此問題的方法把全局靜態(tài)對象鎖住,因為賬號是唯一的

    2024年02月10日
    瀏覽(23)
  • SpringBoot集成Elasticsearch客戶端(新舊版本)(2023-01-28)

    SpringBoot集成Elasticsearch客戶端(新舊版本)(2023-01-28)

    第一章 SpringBoot集成ElasticSearch(2023-01-28) 例如:業(yè)務中需要使用es,所以做一些客戶端選型,熟悉一下基本的操作,所以記錄這篇博客,有關概念理論性的文章還在整理過程中,后續(xù)會整理個系列 Spring認證中國教育管理中心-Spring Data Elasticsearch教程一 SpringData集成Elasticsearch Sp

    2024年02月07日
    瀏覽(25)
  • Springboot 集成WebSocket作為客戶端,含重連接功能,開箱即用

    使用演示 只需要init后調用sendMessage方法即可,做到開箱即用。內部封裝了失敗重連接、斷線重連接等功能。 基于Springboot工程 引入websocket依賴 開箱即用的工具類

    2024年02月04日
    瀏覽(36)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包