Java opc ua 批量订阅与服务断开重新连接

Maven依赖

      <!--Client SDK依赖--> 		
	  <dependency>
   			<groupId>org.eclipse.milo</groupId>
      		<artifactId>sdk-client</artifactId> 			
      		<version>0.2.4</version>
      </dependency>
      		
      <!--Server SDK依赖--> 		
      <dependency> 			
        	<groupId>org.eclipse.milo</groupId>
      		<artifactId>sdk-server</artifactId> 			
      		<version>0.2.4</version>
      </dependency>
      
      <!-- Stack依赖-->
	  <dependency>
			<groupId>org.eclipse.milo</groupId>
			<artifactId>stack-client</artifactId>
			<version>0.2.4</version>
	  </dependency>
	  <dependency>
			<groupId>org.eclipse.milo</groupId>
			<artifactId>stack-server</artifactId>
			<version>0.2.4</version>
	  </dependency>
	  
	  <!--Milo客户端的依赖-->
	  <dependency>
			<groupId>org.eclipse.milo</groupId>
			<artifactId>sdk-client</artifactId>
			<version>0.2.4</version>
	  </dependency>

opc ua连接

   @Component  
   public class OpcUaConfig { 	  	
   public static UaClient opcLink; 	  
   
    /**
    * opc ua  打开连接订阅
    *	res  是否需要重复连接
    * @throws Exception
    */    
  public void createSubscription(boolean res) {
       try {
       	  //等待三秒
           Thread.sleep(3 * 1000);
           UaClient uaClient = null; 
           // 连接地址,我这是存在数据库里
           //String EndPointUrl = "opc.tcp://ip:端口";
           String EndPointUrl = configService.selectConfigByKey("sys.opcUa.url");
           //安全策略选择
           EndpointDescription[] endpointDescription = UaTcpStackClient.getEndpoints(EndPointUrl).get();
           //过滤掉不需要的安全策略,选择一个自己需要的安全策略
           EndpointDescription endpoint = Arrays.stream(endpointDescription)
                   .filter(e -> e.getSecurityPolicyUri().equals(None.getSecurityPolicyUri()))
                   .findFirst().orElseThrow(() -> new Exception("no desired endpoints returned"));
   
           OpcUaClientConfig config = OpcUaClientConfig.builder()
                   .setApplicationName(LocalizedText.english("bim")) // opc ua 别名      
                    // .setIdentityProvider(new AnonymousProvider())
                    // .setIdentityProvider(new UsernameProvider("OPCUser","123456"))
                   .setApplicationUri(EndPointUrl)// 地址
                   .setEndpoint(endpoint)// 安全策略等配置
                   .setRequestTimeout(uint(10000)) //等待时间
                   .build();
   
           OpcUaClient opcClient = new OpcUaClient(config);// 准备连接\
           uaClient = opcClient.connect().get();
           opcLink = uaClient;
       }catch (Exception e){
               if(res){
               	//重复连接
                   createSubscription(true);
               }else{
                   System.out.println(e.getMessage());
               }
       }    
    }
  }

}

批量订阅及重新连接

@Component
public class DeviceOpenConfigProcess implements Runnable {
	private static final Logger LOGGER = LoggerFactory.getLogger(DeviceOpenConfigProcess.class);
	@Autowired
    public RedisCache redisCache;

    /**
     * 自定义订阅监听
     */
    private class CustomSubscriptionListener implements UaSubscriptionManager.SubscriptionListener {


        public void onKeepAlive(UaSubscription subscription, DateTime publishTime) {
            System.out.println("opcUa监听:onKeepAlive(连接存活中)");
        }

        public void onStatusChanged(UaSubscription subscription, StatusCode status) {
            System.out.println("opcUa监听:onStatusChanged(连接状态改变)");
        }

        public void onPublishFailure(UaException exception) {
            System.out.println("opcUa监听:onPublishFailure(连接断开)");
            //连接断开记录
            opcUaConfig.opcuaRecord();
          
        }

        public void onNotificationDataLost(UaSubscription subscription) {
            System.out.println("opcUa监听:onNotificationDataLost(数据丢失)");
        }

        /**
         * 重连时 尝试恢复之前的订阅失败时 会调用此方法
         *
         * @param uaSubscription 订阅
         * @param statusCode     状态
         */
        public void onSubscriptionTransferFailed(UaSubscription uaSubscription, StatusCode statusCode) {
            //在回调方法中重新订阅
            System.out.println("opcUa监听:正在重新启动订阅");
             // 获取OPC UA服务器  --参数true就是是否需要重复连接
            opcUaConfig.createSubscription(true);
            //重启
            run();
        }
    }

    public void run() {
        deviceOpenConfig(OpcUaConfig.opcLink);
    }
    /**
    *	批量订阅
    */
    public void deviceOpenConfig(UaClient opcClient){
        try {
            //再创建好订阅对象之后将监听加到 SubscriptionManager 里   ------>监听
            opcClient.getSubscriptionManager().addSubscriptionListener(new CustomSubscriptionListener());
            //我这里是从redis中获取到的,当然也可以从数据读取,看自己业务需要怎么处理 ----我这里的订阅参数是动态的
            //注:OpcUaParameter 是自己自定义的实体
            List<OpcUaParameter> key = redisCache.getCacheList("deviceOpenConfig");
            if (StringUtils.isNotNull(key)) {
                //创建发布间隔1000ms的订阅对象
                UaSubscription subscription = opcClient.getSubscriptionManager().createSubscription(1000).get();
                for (int i = 0; i < key.size(); i++) {
                    String node = key.get(i).getFieldName();
                    Integer index = key.get(i).getFieldNameIndex();
                    //创建订阅的变量
                    NodeId nodeId = new NodeId(index, node);
                    ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
                    //创建监控的参数
                    MonitoringParameters parameters = new MonitoringParameters(
                            uint(1 + i),  // 为了保证唯一性,否则key值一致
                            0.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<UaMonitoredItem> items = subscription.createMonitoredItems(
                            TimestampsToReturn.Both,
                            newArrayList(request),
                            (item, id) -> {
                                item.setValueConsumer((is, value) -> {
                                    //检测redis是否发生了变化  ---redis更新可以忽略
                                    List<OpcUaParameter> lists = redisCache.getCacheList("deviceOpenConfig");
                                    //判断key与lists对象是否相同
                                    Boolean exist = opcUaConfig.exist(key, lists);
                                    if (exist) {
                                        System.out.println("---------deviceOpenConfig缓存数据发生了变化------------");
                                        deviceOpenConfig(opcClient);
                                    }
                                    String nodeName = item.getReadValueId().getNodeId().getIdentifier().toString();
                                    String nodeValue = value.getValue().getValue().toString();
                                    System.out.println("参数:"+nodeName+"-----------值:"+nodeValue);
                                });
                            }).get();
                }
            } else {
                LOGGER.info("暂无采集数据");
                Thread.sleep(3 * 1000);
                //重新执行本方法
                deviceOpenConfig(opcClient);
            }
        } catch (Exception e) {
            LOGGER.error("----------参数出现异常----------");
            LOGGER.error(e.getMessage());
        }
    }
}

注:DeviceOpenConfigProcess implements Runnable 是因为我们的业务线不只是单单只有这一个批量订阅,如果你的业务只是单业务线批量订阅可以在服务启动成功后进行执行。以上就是我目前所处理方法,第一次接触,本人知识有限,如果还有更好的方法或者有什么不对的可以提出。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

✎﹏ℳ๓₯㎕じ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值