Java对接OPC UA

一、需求

使用java对接西门子S7-1500,之前都是通过偏移量直接读取寄存器地址,通过注解 @S7Variable(address = “DB800.8.0”, type = EDataType.BOOL) 就完成。

<dependency>
    <groupId>com.github.xingshuangs</groupId>
    <artifactId>iot-communication</artifactId>
    <version>1.4.4</version>
</dependency>

现在PLC方说使用符号的方式,如下图:
在这里插入图片描述
于是技术栈选型使用Milo库的方式进行对接。

二、PLC需要提供的内容

  1. 连接地址:opc.tcp://10.19.171.XX:4840。
  2. NodeId:一般不改的话默认是3。
  3. Identifier:对应实际接口里的完整字段路径,PLC可以在他们的软件中找到或者Java开发根据接口自己拼接都可以。
    在这里插入图片描述

三、Java程序开发准备

  1. 引入依赖,在pom.xml文件中新增
        <dependency>
           <groupId>org.eclipse.milo</groupId>
           <artifactId>sdk-client</artifactId>
           <version>0.6.8</version>
       </dependency>
  1. 创建连接(以下是无安全验证方式连接),以下的连接只是为了拿到opcUaClient对象,后续的所有读写订阅都是通过opcUaClient进行操作的。

   private static final String endpointUrl = "opc.tcp://10.19.171.xx:4840";
   public static OpcUaClient opcUaClient;
   public static void main(String[] args) {
       try {
           SecurityPolicy securityPolicy = SecurityPolicy.None;
           List<EndpointDescription> endpoints;
           try {
               endpoints = DiscoveryClient.getEndpoints(endpointUrl).get();
           } catch (Throwable ex) {
               // 发现服务
               String discoveryUrl = endpointUrl;
               if (!discoveryUrl.endsWith("/")) {
                   discoveryUrl += "/";
               }
               discoveryUrl += "discovery";
               endpoints = DiscoveryClient.getEndpoints(discoveryUrl).get();
           }
           EndpointDescription endpoint = endpoints.stream()
                   .filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getUri()))
                   .findFirst()
                   .orElseThrow(() -> new Exception("没有连接上端点"));

           OpcUaClientConfig config = OpcUaClientConfig.builder()
                   .setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
                   .setApplicationUri("urn:eclipse:milo:examples:client")
                   //.setCertificate(loader.getClientCertificate())
                   //.setKeyPair(loader.getClientKeyPair())
                   .setEndpoint(endpoint)
                   //根据匿名验证和第三个用户名验证方式设置传入对象 AnonymousProvider(匿名方式)UsernameProvider(账户密码)new UsernameProvider("admin","123456")
                   .setIdentityProvider(new AnonymousProvider())
                   .setRequestTimeout(UInteger.valueOf(5000))
                   .build();
           opcUaClient = OpcUaClient.create(config);
       } catch (Exception e) {
           System.out.println("创建客户端失败");
       }
   }
  1. 数据读取
    public static void readValue() throws ExecutionException, InterruptedException {
        // 获取全局opcUaClient创建连接
        opcUaClient.connect().get();
        // 注意这里"\"LES_DB\".\"OP30_materialShel01\".\"Rec\".\"TakeCmpl\""里面需要用双引号,最终效果就是这样
        NodeId nodeId = new NodeId(3, "\"LES_DB\".\"OP30_materialShel01\".\"Rec\".\"TakeCmpl\"");
        DataValue value = opcUaClient.readValue(0.0, TimestampsToReturn.Both, nodeId).get();
        System.out.println("数据读取,值为:" + value.getValue().getValue());
    }
    
  1. 数据写入
 public static void writeValue(boolean value) throws ExecutionException, InterruptedException {
     // 获取全局opcUaClient创建连接
     opcUaClient.connect().get();
     //创建变量节点
     NodeId nodeId = new NodeId(3, "\"LES_DB\".\"OP30_materialShel01\".\"Rec\".\"TakeCmpl\"");
     //创建Variant对象和DataValue对象
     Variant v = new Variant(value);
     DataValue dataValue = new DataValue(v, null, null);
     StatusCode statusCode = opcUaClient.writeValue(nodeId, dataValue).get();
     System.out.println("写入结果:" + statusCode.isGood());
 }
  1. 数据订阅,如果你有当数据变化时候进行事件触发时候则可以使用订阅的方式
    public static void createSubscription() throws ExecutionException, InterruptedException {
        //创建连接
        opcUaClient.connect().get();
        //创建发布间隔1000ms的订阅对象
        UaSubscription subscription = opcUaClient.getSubscriptionManager().createSubscription(1000.0).get();
        //创建订阅的变量
        NodeId nodeId = new NodeId(3, "\"LES_DB\".\"OP30_materialShel01\".\"Rec\".\"TakeCmpl\"");
        ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
        //创建监控的参数
        MonitoringParameters parameters = new MonitoringParameters(
                uint(1),
                1000.0,     // sampling interval
                null,       // filter, null means use default
                uint(10),   // queue size
                true        // discard oldest
        );
        //创建监控项请求
        //该请求最后用于创建订阅。
        MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);
        List<MonitoredItemCreateRequest> requests = new ArrayList<>();
        requests.add(request);
        //创建监控项,并且注册变量值改变时候的回调函数。
        List<UaMonitoredItem> items = subscription.createMonitoredItems(
                TimestampsToReturn.Both,
                requests,
                (item, id) -> {
                    item.setValueConsumer((item2, value) -> {
                        System.out.println("nodeid :" + item.getReadValueId().getNodeId());
                        System.out.println("value :" + value.getValue().getValue());
                    });
                }
        ).get();
    }
    

四、总结

用符号的方式来对接PLC操作还是比较零碎的,主要是没有现成的框架能够将plc接口内容直接映射成java对象,当大量接口需要对接时体会尤为明显,这就需要java开发对接口内容再进行封装使得满足自己的业务需求。
我试过接口路径拿到LES_DB.OP30_materialShel01.Rec,打印结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十五001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值