文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java模拟OPC Server服务器并创建节点代码实现

2023-09-27 14:53

关注

前言

模拟OPC Server服务器的方法除了使用KEPServerEX6软件以外,还可以使用java代码模拟启动一个opc server。下文详细讲解,如何使用java代码,实现模拟一个或者多个opc server服务器。

OPC Server简介

OPC(OLE for Process Control)Server是一种用于实时数据通信的标准化软件接口,它允许不同厂商的设备和软件系统之间进行数据交换和集成。以下是对OPC Server的详细解释:

总结而言,OPC Server是一种用于工业自动化中实时数据通信的标准化软件接口。它通过提供统一的接口和协议,连接了底层设备和上层应用软件,实现了设备之间的数据交换和集成。通过使用OPC Server,企业可以实现设备和系统的互联互通,提高生产效率和管理水平。

引入依赖

首先在Maven项目的pom.xml文件中引入所需的依赖

<dependency><groupId>org.eclipse.milogroupId><artifactId>sdk-serverartifactId><version>0.6.9version>dependency><dependency><groupId>org.eclipse.milogroupId><artifactId>dictionary-managerartifactId><version>0.6.9version>dependency>

创建Server

创建opc server代码实现:

       private OpcUaServer startServer(int port){        Set<EndpointConfiguration> endpointConfigurations=new HashSet<>();        EndpointConfiguration endpointConfiguration=EndpointConfiguration.newBuilder().setBindPort(port).build();        endpointConfigurations.add(endpointConfiguration);        System.out.println(endpointConfiguration.getEndpointUrl());        OpcUaServerConfig serverConfig = OpcUaServerConfig.builder()                .setApplicationName(LocalizedText.english("Server Application"))                .setApplicationUri("urn:eclipse:milo:examples:server")                .setProductUri("urn:eclipse:milo:examples:server")                .setEndpoints(endpointConfigurations)                .build();        OpcUaServer server = new OpcUaServer(serverConfig);        server.startup();        return server;    }

在EndpointConfiguration的newBuilder方法中,我看可以知道,如果我们不设置端口,默认就是 12685.
在这里插入图片描述

创建自定义Namespace

创建TestNamespace类,继承org.eclipse.milo sdk-server 中的ManagedNamespaceWithLifecycle类,并声明构造器,代码如下:

public static final String NAMESPACE_URI = "urn:eclipse:milo:opc";    private final Logger logger = LoggerFactory.getLogger(getClass());    private volatile Thread eventThread;    private volatile boolean keepPostingEvents = true;    private final DataTypeDictionaryManager dictionaryManager;    private final SubscriptionModel subscriptionModel;    public TestNamespace(OpcUaServer server) {        super(server, NAMESPACE_URI);        subscriptionModel = new SubscriptionModel(server, this);        dictionaryManager = new DataTypeDictionaryManager(getNodeContext(), NAMESPACE_URI);        getLifecycleManager().addLifecycle(dictionaryManager);        getLifecycleManager().addLifecycle(subscriptionModel);        getLifecycleManager().addLifecycle(new Lifecycle() {            @Override            public void startup() {                startBogusEventNotifier();            }            @Override            public void shutdown() {                try {                    keepPostingEvents = false;                    eventThread.interrupt();                    eventThread.join();                } catch (InterruptedException ignored) {                    // ignored                }            }        });    }

重载Lifecycle的方法

重载org.eclipse.milo.opcua.sdk.server.Lifecycle 的 startup方法和shutdown方法,启动时,创建事件通知器。代码如下:

    private void startBogusEventNotifier() {        // Set the EventNotifier bit on Server Node for Events.        UaNode serverNode = getServer()                .getAddressSpaceManager()                .getManagedNode(Identifiers.Server)                .orElse(null);        if (serverNode instanceof ServerTypeNode) {            ((ServerTypeNode) serverNode).setEventNotifier(ubyte(1));            // Post a bogus Event every couple seconds            eventThread = new Thread(() -> {                while (keepPostingEvents) {                    try {                        BaseEventTypeNode eventNode = getServer().getEventFactory().createEvent(    newNodeId(UUID.randomUUID()),    Identifiers.BaseEventType                        );                        eventNode.setBrowseName(new QualifiedName(1, "foo"));                        eventNode.setDisplayName(LocalizedText.english("foo"));                        eventNode.setEventId(ByteString.of(new byte[]{0, 1, 2, 3}));                        eventNode.setEventType(Identifiers.BaseEventType);                        eventNode.setSourceNode(serverNode.getNodeId());                        eventNode.setSourceName(serverNode.getDisplayName().getText());                        eventNode.setTime(DateTime.now());                        eventNode.setReceiveTime(DateTime.NULL_VALUE);                        eventNode.setMessage(LocalizedText.english("event message!"));                        eventNode.setSeverity(ushort(2));                        //noinspection UnstableApiUsage                        getServer().getEventBus().post(eventNode);                        eventNode.delete();                    } catch (Throwable e) {                        logger.error("Error creating EventNode: {}", e.getMessage(), e);                    }                    try {                        //noinspection BusyWait                        Thread.sleep(2_000);                    } catch (InterruptedException ignored) {                        // ignored                    }                }            }, "bogus-event-poster");            eventThread.start();        }    }

创建opc ua 节点方法

       public void addNodes(Set<String> keys) {        // Create a "opc" folder and add it to the node manager        NodeId folderNodeId = newNodeId("opc");        UaFolderNode folderNode = new UaFolderNode(                getNodeContext(),                folderNodeId,                newQualifiedName("opc"),                LocalizedText.english("opc")        );        getNodeManager().addNode(folderNode);        // Make sure our new folder shows up under the server's Objects folder.        folderNode.addReference(new Reference(                folderNode.getNodeId(),                Identifiers.Organizes,                Identifiers.ObjectsFolder.expanded(),                false        ));        for (String key : keys) {            NodeId typeId = Identifiers.Double;            Variant variant = new Variant(0d);            UaVariableNode node = new UaVariableNode.UaVariableNodeBuilder(getNodeContext())                    .setNodeId(newNodeId(key))                    .setAccessLevel(AccessLevel.READ_WRITE)                    .setUserAccessLevel(AccessLevel.READ_WRITE)                    .setBrowseName(newQualifiedName(key))                    .setDisplayName(LocalizedText.english(key))                    .setDataType(typeId)                    .setTypeDefinition(Identifiers.BaseDataVariableType)                    .build();            node.setValue(new DataValue(variant));            getNodeManager().addNode(node);            folderNode.addOrganizes(node);        }    }

先创建一个“opc”文件夹并将其添加到节点管理器中,然后根据传入的节点名称,循环遍历,创建到“opc”文件夹下,生成变量类型的节点。

重载ManagedNamespaceWithLifecycle虚拟方法

重载继承类ManagedNamespaceWithLifecycle的虚拟方法
代码如下:

    @Override    public void onDataItemsCreated(List<DataItem> dataItems) {        subscriptionModel.onDataItemsCreated(dataItems);    }    @Override    public void onDataItemsModified(List<DataItem> dataItems) {        subscriptionModel.onDataItemsModified(dataItems);    }    @Override    public void onDataItemsDeleted(List<DataItem> dataItems) {        subscriptionModel.onDataItemsDeleted(dataItems);    }    @Override    public void onMonitoringModeChanged(List<MonitoredItem> monitoredItems) {        subscriptionModel.onMonitoringModeChanged(monitoredItems);    }

完整代码实现:

import org.eclipse.milo.opcua.sdk.core.AccessLevel;import org.eclipse.milo.opcua.sdk.core.Reference;import org.eclipse.milo.opcua.sdk.server.Lifecycle;import org.eclipse.milo.opcua.sdk.server.OpcUaServer;import org.eclipse.milo.opcua.sdk.server.api.DataItem;import org.eclipse.milo.opcua.sdk.server.api.ManagedNamespaceWithLifecycle;import org.eclipse.milo.opcua.sdk.server.api.MonitoredItem;import org.eclipse.milo.opcua.sdk.server.dtd.DataTypeDictionaryManager;import org.eclipse.milo.opcua.sdk.server.model.nodes.objects.BaseEventTypeNode;import org.eclipse.milo.opcua.sdk.server.model.nodes.objects.ServerTypeNode;import org.eclipse.milo.opcua.sdk.server.nodes.UaFolderNode;import org.eclipse.milo.opcua.sdk.server.nodes.UaNode;import org.eclipse.milo.opcua.sdk.server.nodes.UaVariableNode;import org.eclipse.milo.opcua.sdk.server.util.SubscriptionModel;import org.eclipse.milo.opcua.stack.core.Identifiers;import org.eclipse.milo.opcua.stack.core.types.builtin.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.*;import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte;import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ushort;public class TestNamespace extends ManagedNamespaceWithLifecycle {    public static final String NAMESPACE_URI = "urn:eclipse:milo:opc";    private final Logger logger = LoggerFactory.getLogger(getClass());    private volatile Thread eventThread;    private volatile boolean keepPostingEvents = true;    private final DataTypeDictionaryManager dictionaryManager;    private final SubscriptionModel subscriptionModel;    public TestNamespace(OpcUaServer server) {        super(server, NAMESPACE_URI);        subscriptionModel = new SubscriptionModel(server, this);        dictionaryManager = new DataTypeDictionaryManager(getNodeContext(), NAMESPACE_URI);        getLifecycleManager().addLifecycle(dictionaryManager);        getLifecycleManager().addLifecycle(subscriptionModel);        getLifecycleManager().addLifecycle(new Lifecycle() {            @Override            public void startup() {                startBogusEventNotifier();            }            @Override            public void shutdown() {                try {                    keepPostingEvents = false;                    eventThread.interrupt();                    eventThread.join();                } catch (InterruptedException ignored) {                    // ignored                }            }        });    }        public void addNodes(Set<String> keys) {        // Create a "HelloWorld" folder and add it to the node manager        NodeId folderNodeId = newNodeId("opc");        UaFolderNode folderNode = new UaFolderNode(                getNodeContext(),                folderNodeId,                newQualifiedName("opc"),                LocalizedText.english("opc")        );        getNodeManager().addNode(folderNode);        // Make sure our new folder shows up under the server's Objects folder.        folderNode.addReference(new Reference(                folderNode.getNodeId(),                Identifiers.Organizes,                Identifiers.ObjectsFolder.expanded(),                false        ));        for (String key : keys) {            NodeId typeId = Identifiers.Double;            Variant variant = new Variant(0d);            UaVariableNode node = new UaVariableNode.UaVariableNodeBuilder(getNodeContext())                    .setNodeId(newNodeId(key))                    .setAccessLevel(AccessLevel.READ_WRITE)                    .setUserAccessLevel(AccessLevel.READ_WRITE)                    .setBrowseName(newQualifiedName(key))                    .setDisplayName(LocalizedText.english(key))                    .setDataType(typeId)                    .setTypeDefinition(Identifiers.BaseDataVariableType)                    .build();            node.setValue(new DataValue(variant));            getNodeManager().addNode(node);            folderNode.addOrganizes(node);        }    }    private void startBogusEventNotifier() {        // Set the EventNotifier bit on Server Node for Events.        UaNode serverNode = getServer()                .getAddressSpaceManager()                .getManagedNode(Identifiers.Server)                .orElse(null);        if (serverNode instanceof ServerTypeNode) {            ((ServerTypeNode) serverNode).setEventNotifier(ubyte(1));            // Post a bogus Event every couple seconds            eventThread = new Thread(() -> {                while (keepPostingEvents) {                    try {                        BaseEventTypeNode eventNode = getServer().getEventFactory().createEvent(    newNodeId(UUID.randomUUID()),    Identifiers.BaseEventType                        );                        eventNode.setBrowseName(new QualifiedName(1, "foo"));                        eventNode.setDisplayName(LocalizedText.english("foo"));                        eventNode.setEventId(ByteString.of(new byte[]{0, 1, 2, 3}));                        eventNode.setEventType(Identifiers.BaseEventType);                        eventNode.setSourceNode(serverNode.getNodeId());                        eventNode.setSourceName(serverNode.getDisplayName().getText());                        eventNode.setTime(DateTime.now());                        eventNode.setReceiveTime(DateTime.NULL_VALUE);                        eventNode.setMessage(LocalizedText.english("event message!"));                        eventNode.setSeverity(ushort(2));                        //noinspection UnstableApiUsage                        getServer().getEventBus().post(eventNode);                        eventNode.delete();                    } catch (Throwable e) {                        logger.error("Error creating EventNode: {}", e.getMessage(), e);                    }                    try {                        //noinspection BusyWait                        Thread.sleep(2_000);                    } catch (InterruptedException ignored) {                        // ignored                    }                }            }, "bogus-event-poster");            eventThread.start();        }    }    @Override    public void onDataItemsCreated(List<DataItem> dataItems) {        subscriptionModel.onDataItemsCreated(dataItems);    }    @Override    public void onDataItemsModified(List<DataItem> dataItems) {        subscriptionModel.onDataItemsModified(dataItems);    }    @Override    public void onDataItemsDeleted(List<DataItem> dataItems) {        subscriptionModel.onDataItemsDeleted(dataItems);    }    @Override    public void onMonitoringModeChanged(List<MonitoredItem> monitoredItems) {        subscriptionModel.onMonitoringModeChanged(monitoredItems);    }}

创建OpcServerTest类,进行使用测试:

import org.eclipse.milo.opcua.sdk.server.OpcUaServer;import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig;import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;import org.eclipse.milo.opcua.stack.server.EndpointConfiguration;import java.io.*;import java.nio.charset.StandardCharsets;import java.util.HashSet;import java.util.Set;public class OpcServerTest {    public static void main(String[] args) {        OpcUaServer server=startServer(12688);        TestNamespace namespace=new TestNamespace(server);        Set<String> keys=getAllKeys("ehc.txt");        namespace.addNodes(keys);        namespace.startup();    }        private static OpcUaServer startServer(int port){        Set<EndpointConfiguration> endpointConfigurations=new HashSet<>();        EndpointConfiguration endpointConfiguration=EndpointConfiguration.newBuilder().setBindPort(port).build();        endpointConfigurations.add(endpointConfiguration);        System.out.println(endpointConfiguration.getEndpointUrl());        OpcUaServerConfig serverConfig = OpcUaServerConfig.builder()                .setApplicationName(LocalizedText.english("Server Application"))                .setApplicationUri("urn:eclipse:milo:examples:server")                .setProductUri("urn:eclipse:milo:examples:server")                .setEndpoints(endpointConfigurations)                .build();        OpcUaServer server = new OpcUaServer(serverConfig);        server.startup();        return server;    }    private static Set<String> getAllKeys(String fileName){        Set<String> keys=new HashSet<>(50);        try {            InputStream is=  OpcServerTest.class.getResourceAsStream("/points/"+fileName);            InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8);            BufferedReader in = new BufferedReader(reader);            String line;            while ((line = in.readLine()) != null) {                keys.add(line);            }        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        return  keys;    }}

我把需要创建的点位都放在java maven项目的resources文件下的ehc.txt文件中,通过getAllKeys方法拿到所有的需要创建的点位集合。
在这里插入图片描述
在这里插入图片描述
启动main方法,控制台输出如下:
在这里插入图片描述
在这里插入图片描述

我们可以看到控制台输出的 opc.tcp://localhost:12688 就是我们使用java启动opc ua server的连接地址,上面的启动server的代码中,没有设置用户,密码登录,我们在使用opc ua 客户端的时候,可以使用匿名登录访问。

OPC UA 客户端连接测试

使用java 代码连接我们刚才创建的 Opc Ua server,尝试读取我们创建的节点名称,代码如下:

import org.eclipse.milo.opcua.sdk.client.OpcUaClient;public class OpcUaClientTest {    public static void main(String[] args) throws Exception {        String endPointUrl="opc.tcp://localhost:12688";        OpcUaClient client=OpcUaUtil.createClient(endPointUrl,null,null);        OpcUaUtil.browse(null,client);        Thread.sleep(Integer.MAX_VALUE);    }}

经测试,连接读取节点名称成功,控制台输出如下:
在这里插入图片描述

来源地址:https://blog.csdn.net/weixin_40986713/article/details/131513885

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-服务器
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯