Java与opc通信之一 - opc ua(milo)
这篇文章介绍如何使用opc ua的方式,访问opc数据。
1、引入依赖
<!-- milo连接opc --> <dependency> <groupId>org.eclipse.milo</groupId> <artifactId>sdk-client</artifactId> <version>0.6.8</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>org.eclipse.milo</groupId> <artifactId>sdk-server</artifactId> <version>0.6.8</version> </dependency> <dependency> <groupId>org.eclipse.milo</groupId> <artifactId>dictionary-reader</artifactId> <version>0.6.0</version> </dependency> <dependency> <groupId>org.eclipse.milo</groupId> <artifactId>dictionary-manager</artifactId> <version>0.6.0</version> </dependency>
2、初始化opc ua客户端
@Component public class ClientGen { //加载加密类型 static { Security.addProvider(new BouncyCastleProvider()); } private final Logger log = LoggerFactory.getLogger(getClass()); // milo用来连接opc ua的client public static OpcUaClient opcUaClient; @Autowired private OpcUaConfig opcUaConfig; /** * 创建opc ua客户端(在项目启动的时候执行该方法) * */ @PostConstruct public void createClient_() throws UaException { String endPoint = opcUaConfig.getEndpointUrl(); opcUaClient = OpcUaClient.create( endPoint, endpointDescriptions -> { final List<EndpointDescription> collect = endpointDescriptions.stream().collect(Collectors.toList()); final Optional<EndpointDescription> first = endpointDescriptions .stream() .findFirst(); System.out.println(first.get().getSecurityPolicyUri()); return Optional.of(collect.get(0)); }, configBuilder -> configBuilder .setApplicationName(LocalizedText.english("opc-ua client")) .setApplicationUri(endPoint) // .setIdentityProvider(new UsernameProvider(username, password)) .setIdentityProvider(new AnonymousProvider()) .setRequestTimeout(uint(5000)) .build() ); log.info("创建客户端:{} 成功!", opcUaClient); } /** * 创建opc ua客户端(在项目启动的时候执行该方法) * */ public void createClient(){ try { Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security"); Files.createDirectories(securityTempDir); if (!Files.exists(securityTempDir)) { throw new Exception("没有创建安全目录: " + securityTempDir); } log.info("安全目录: {}", securityTempDir.toAbsolutePath()); //加载秘钥 KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir); //安全策略 None、Basic256、Basic128Rsa15、Basic256Sha256 SecurityPolicy securityPolicy = SecurityPolicy.None; List<EndpointDescription> endpoints; try { endpoints = DiscoveryClient.getEndpoints(opcUaConfig.getEndpointUrl()).get(); } catch (Throwable ex) { String discoveryUrl = opcUaConfig.getEndpointUrl(); if (!discoveryUrl.endsWith("/")) { discoveryUrl += "/"; } discoveryUrl += "discovery"; log.info("开始连接 URL: {}", discoveryUrl); endpoints = DiscoveryClient.getEndpoints(discoveryUrl).get(); } EndpointDescription endpoint = endpoints.stream() .filter(e -> e.getEndpointUrl().equals(opcUaConfig.getEndpointUrl())) .findFirst().orElseThrow(() -> new Exception("没有节点返回")); //.filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getUri())) //.filter(opcUaConfig.endpointFilter()) //.findFirst() //.orElseThrow(() -> new Exception("没有连接上端点")); log.info("使用端点: {} [{}/{}]", endpoint.getEndpointUrl(), securityPolicy, endpoint.getSecurityMode()); 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(账户密码) .setIdentityProvider(new AnonymousProvider()) .setRequestTimeout(uint(100000000)) .build(); opcUaClient = OpcUaClient.create(config); log.info("创建客户端:{} 成功!", opcUaClient); } catch (Exception e) { log.error("创建客户端失败" + e.getMessage()); } } }
3、批量采集opc实时数据
/** * 采集一标段和二标段的数据 */ private List<DbBlockDto> gatherSectionOneData(List<NodeId> nodeIds) throws ExecutionException, InterruptedException { List<DbBlockDto> dtoList = new ArrayList<>(); // 获取opc ua客户端 OpcUaClient client = ClientGen.opcUaClient; log.info("client is: {}", client); // 链接opc ua client.connect().get(); // 批量采集数据 final CompletableFuture<List<DataValue>> data = client.readValues(0d, TimestampsToReturn.Neither, nodeIds); List<DataValue> dataValues = data.get(); if (dataValues == null) { return dtoList; } // 封装数据 for (int i = 0; i < dataValues.size(); i++) { DbBlockDto dbBlockDto = new DbBlockDto(); DataValue value = dataValues.get(i); dbBlockDto.setName(nodeIds.get(i).getIdentifier().toString().substring(2)); // 校验数据 if(value.getStatusCode() != null){ if (value.getStatusCode().isGood()) { String plcValue = value.getValue().getValue().toString(); dbBlockDto.setValue(plcValue); } } dtoList.add(dbBlockDto); } return dtoList; }
注:1、读取数据时,需要将业务变量名称封装成 “t|业务字段”的形式
// 将二标段DB块的变量名称,拼接成t|xxx的格式 blocks.parallelStream().forEach(n -> n.setName("t|" + n.getName())); List<NodeId> nodeIdList = new ArrayList<>(); for(DbBlock dbBlock : blocks){ NodeId nodeId = new NodeId(1, dbBlock.getName()); nodeIdList.add(nodeId); }
2、本机的host文件需要配置为opc服务器的服务地址
public String getEndpointUrl() { return "opc.tcp://XmcWinCCServer:4862"; }