当前位置: 首页 > news >正文

[转]Java实现OPC UA客户端

原文地址:Java实现OPC UA客户端一、Milo库 本文使用Milo库实现OPC UA客户端,以达到通过java读、写、订阅变 - 掘金

一、Milo库

本文使用Milo库实现OPC UA客户端,以达到通过java读、写、订阅变量的目的。

官网:Milo Github链接

官网地址有时候访问很慢,也可以使用国内的地址:gitcode.net/mirrors/ecl…

相关博客资料(转载):blog.csdn.net/q932104843/…

二、OPC UA服务端及客户端

OPC UA服务端:KEPServerEX 6

  • 下载地址:www.sibotech.net/SiboKepware…
  • Kepware 配置 OPC UA 实现匿名 or 用户名/密码连接:ld246.com/article/161…

UI客户端:

  • UaExpert 下载地址:www.unified-automation.com/
  • UaExpert使用教程(转载):www.cnblogs.com/water-sea/p…

三、Java连接OPC UA服务端

以下代码都是在一个类中执行的,并使用main方法进行测试,所有方法都是private和static修饰的。

3.1 依赖

Milo的依赖有2个,Client SDK,Server SDK。

客户端:

 
xml
体验AI代码助手
代码解读
复制代码
<!--Milo客户端的依赖-->
<dependency>
  <groupId>org.eclipse.milo</groupId>
  <artifactId>sdk-client</artifactId>
  <version>0.6.3</version>
</dependency>

服务端:

 
xml
体验AI代码助手
代码解读
复制代码
<!--Milo服务端的依赖-->
<dependency>
  <groupId>org.eclipse.milo</groupId>
  <artifactId>sdk-server</artifactId>
  <version>0.6.3</version>
</dependency>

3.2 创建opc ua客户端

 
java
体验AI代码助手
代码解读
复制代码
/**
  * 创建OPC UA客户端
  * @return
  * @throws Exception
  */
private static OpcUaClient createClient() throws Exception {
  //opc ua服务端地址
  private final static String endPointUrl = "opc.tcp://192.168.0.169:49320";
  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);
  }
  return 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()
                           );
}

注意:

  1. new AnonymousProvider()表示使用匿名方式访问,也可以通过new UsernameProvider(userName, password)方式访问。
  2. 如果需要使用数字证书和秘钥的方式进行认证,请去官网查询相关资料。

3.3 遍历树形节点

 
java
体验AI代码助手
代码解读
复制代码
/**
  * 遍历树形节点
  *
  * @param client OPC UA客户端
  * @param uaNode 节点
  * @throws Exception
  */
private static void browseNode(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) {
    if (Objects.requireNonNull(nd.getBrowseName().getName()).contains("_")) {
      continue;
    }
    System.out.println("Node= " + nd.getBrowseName().getName());
    browseNode(client, nd);
  }
}

3.4 读取节点数据

 
java
体验AI代码助手
代码解读
复制代码
/**
  * 读取节点数据
  *
  * @param client OPC UA客户端
  * @throws Exception
  */
private static void readNode(OpcUaClient client) throws Exception {
  int namespaceIndex = 2;
  String identifier = "TD-01.SB-01.AG-01";
  //节点
  NodeId nodeId = new NodeId(namespaceIndex, identifier);
  //读取节点数据
  DataValue value = client.readValue(0.0, TimestampsToReturn.Neither, nodeId).get();
  //标识符
  String identifier = String.valueOf(nodeId.getIdentifier());
  System.out.println(identifier + ": " + String.valueOf(value.getValue().getValue()));
}
  1. namespaceIndex可以通过UaExpert客户端去查询,一般来说这个值是2。
  2. identifier也可以通过UaExpert客户端去查询,这个值=通道名称.设备名称.标记名称

3.5 写入节点数据

 
java
体验AI代码助手
代码解读
复制代码
/**
 * 写入节点数据
 *
 * @param client
 * @throws Exception
 */
private static void writeNodeValue(OpcUaClient client) throws Exception {
    //节点
    NodeId nodeId = new NodeId(2, "TD-01.SB-01.AG-01");
    short i = 3;
    //创建数据对象,此处的数据对象一定要定义类型,不然会出现类型错误,导致无法写入
    DataValue nowValue = new DataValue(new Variant(i), null, null);
    //写入节点数据
    StatusCode statusCode = client.writeValue(nodeId, nowValue).join();
    System.out.println("结果:" + statusCode.isGood());
}

3.5 订阅(单个)

 
java
体验AI代码助手
代码解读
复制代码
/**
 * 订阅(单个)
 *
 * @param client
 * @throws Exception
 */
private static void subscribe(OpcUaClient client) throws Exception {
    //创建发布间隔1000ms的订阅对象
    client
            .getSubscriptionManager()
            .createSubscription(1000.0)
            .thenAccept(t -> {
                //节点
                NodeId nodeId = new NodeId(2, "TD-01.SB-01.AG-01");
                ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
                //创建监控的参数
                MonitoringParameters parameters = new MonitoringParameters(UInteger.valueOf(atomic.getAndIncrement()), 1000.0, null, UInteger.valueOf(10), true);
                //创建监控项请求
                //该请求最后用于创建订阅。
                MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);
                List<MonitoredItemCreateRequest> requests = new ArrayList<>();
                requests.add(request);
                //创建监控项,并且注册变量值改变时候的回调函数。
                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();

    //持续订阅
    Thread.sleep(Long.MAX_VALUE);
}

3.6 批量订阅

 
java
体验AI代码助手
代码解读
复制代码
/**
  * 批量订阅
  *
  * @param client
  * @throws Exception
  */
private static void managedSubscriptionEvent(OpcUaClient client) throws Exception {
  final CountDownLatch eventLatch = new CountDownLatch(1);
	
  //处理订阅业务
  handlerNode(client);

  //持续监听
  eventLatch.await();
}

/**
  * 处理订阅业务
  *
  * @param client OPC UA客户端
  */
private static void handlerNode(OpcUaClient client) {
  try {
    //创建订阅
    ManagedSubscription subscription = ManagedSubscription.create(client);

    //你所需要订阅的key
    List<String> key = new ArrayList<>();
    key.add("TD-01.SB-01.AG-01");
    key.add("TD-01.SB-01.AG-02");

    List<NodeId> nodeIdList = new ArrayList<>();
    for (String s : key) {
      nodeIdList.add(new NodeId(2, s));
    }

    //监听
    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();
  }
}

==注意==:正常情况下通过OpcUaClient去订阅,没问题,但是当服务端断开之后,milo会抛出异常,当服务端重新启动成功后,OpcUaClient可以自动断线恢复,但是恢复之后会发现之前订阅的数据没法访问了。要解决这个问题,只需要断线重连后重新订阅即可。

3.7 处理断线重连后的订阅问题

3.7.1 自定义实现SubscriptionListener

 
java
体验AI代码助手
代码解读
复制代码
/**
  * 自定义订阅监听
  */
private static class CustomSubscriptionListener implements UaSubscriptionManager.SubscriptionListener {

  private OpcUaClient client;

  CustomSubscriptionListener(OpcUaClient client) {
    this.client = client;
  }

  public void onKeepAlive(UaSubscription subscription, DateTime publishTime) {
    logger.debug("onKeepAlive");
  }

  public void onStatusChanged(UaSubscription subscription, StatusCode status) {
    logger.debug("onStatusChanged");
  }

  public void onPublishFailure(UaException exception) {
    logger.debug("onPublishFailure");
  }

  public void onNotificationDataLost(UaSubscription subscription) {
    logger.debug("onNotificationDataLost");
  }

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

3.7.2 添加 SubscriptionListener

 
java
体验AI代码助手
代码解读
复制代码
/**
  * 批量订阅
  *
  * @param client
  * @throws Exception
  */
private static void managedSubscriptionEvent(OpcUaClient client) throws Exception {
  final CountDownLatch eventLatch = new CountDownLatch(1);

  //添加订阅监听器,用于处理断线重连后的订阅问题
  client.getSubscriptionManager().addSubscriptionListener(new CustomSubscriptionListener(client));

  //处理订阅业务
  handlerNode(client);

  //持续监听
  eventLatch.await();
}

3.8 测试

 
java
体验AI代码助手
代码解读
复制代码
public class OpcUaClientTest {

    private static Logger logger = LoggerFactory.getLogger(OpcUaClientTest.class);
    private final static String endPointUrl = "opc.tcp://192.168.0.169:49320";
    private static AtomicInteger atomic = new AtomicInteger(1);

    public static void main(String[] args) throws Exception {
        //创建OPC UA客户端
        OpcUaClient opcUaClient = createClient();

        //开启连接
        opcUaClient.connect().get();

        //遍历节点
        browseNode(opcUaClient, null);

        //读
        readNode(opcUaClient);

        //写
        writeNodeValue(opcUaClient);

        //订阅
        subscribe(opcUaClient);

        //批量订阅
        //managedSubscriptionEvent(opcUaClient);

        //关闭连接
        opcUaClient.disconnect().get();
    }
}

OPC UA常见故障信息代码(转载):blog.csdn.net/ymfz001/art…


作者:买个der
链接:https://juejin.cn/post/7159403514098581540
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
http://www.rkmt.cn/news/68716.html

相关文章:

  • 宽度设置width:100%时 margin不生效问题处理
  • 计算机图形中的法线矩阵:深入理解与应用 - 教程
  • 2025中国管理咨询服务商实力榜:正睿咨询集团领衔,七大领域高潜力本土品牌深度解析
  • 2025年12月的闲谈
  • 2025年上海办公室装修公司排名TOP5:迎湖办公室装修实力
  • 2025年哈尔滨南岗区影视后期培训机构推荐:售后完善的影视后
  • 支持最新unicode 17.0标准,可以输入10万汉字的五笔86输入法
  • 2025 年拼接屏经销商最新推荐榜,技术实力与市场口碑深度解析,高性能与可靠性兼具的优质品牌LED 拼接屏/OLED 拼接屏/液晶拼接屏/DLP 背投拼接屏代理商推荐
  • Ai元人文构想:下一代Ai是大行为模型
  • AI赋能测试开发,周末高薪私教班助你职场进阶!
  • 预生产测试环境时间的评估
  • Docker Compose 主要功能 - jerry
  • 2025年靠谱变频器厂家推荐:5 家实力品牌,覆盖工业+商用多场景
  • 南京混合机供应商综合实力排行榜,烘箱/高温电热鼓风干燥箱/实验室臭氧发生器/大型烘房/三维混合机/混合机混合机产品推荐排行
  • 线上内存泄漏问题,如何快速定位与修复?
  • CSS 文本和字体属性、列表属性 - 详解
  • 2025年制氮机维修定制厂家权威推荐榜单:制氮机设备‌/工业制氮机‌/高压制氮机‌源头厂家精选
  • 推荐几家海外社媒运营推广公司(12月更新),五家优质B2B海外社媒营销公司详细介绍
  • Argocd登录配置
  • MySQL 5.7 二进制安装步骤
  • 2025年上海工业流体设备企业排名,易勒机电设备稳居第一,口
  • 现浇楼梯多少钱一平?专业施工单位推荐,阁楼现浇/楼梯现浇/现浇楼梯/混凝土现浇/楼板搭建公司找哪家
  • 2025年电动护理床工厂权威推荐榜单:医院办公家具‌/候诊椅‌/医用诊疗床‌源头厂家精选
  • 2025年上海免费一键生成原创文章软件平台推荐榜单:上海ai写文案免费一键生成服务/上海文章自动生成服务商/上海AI写文章软件服务商精选
  • 破局AI舆情分析的“最终一公里“:BettaFish多智能体系统深度剖析
  • 2025年地磅厂家推荐,宁波奥普玛衡器专业地磅企业全解析
  • 2025合肥留学机构排名前十
  • 2025年宁波地磅定制服务厂家、耐用型地磅厂家、地磅正规厂商
  • 2025杭州十大留学中介有哪些机构
  • 2025出国留学中介服务