I am new to OPC UA and I am using milo OPC Subscriber client to connect to local discovery service. I have Prosys simulation server which is connected to my local discovery service.
Note: If I connect directly to prosys endpoint it works fine. It fails only through discovery service.
I get the following exception when I run my code
<pre>12:38:35.916 [main] INFO org.eclipse.milo.opcua.stack.core.Stack -
Successfully removed cryptography restrictions. 12:38:36.167 [main]
INFO com.company.OpcuaClientRunner - security temp dir:
C:\Users\Z003Z2YP\AppData\Local\Temp\security 12:38:36.173 [main] INFO
com.company.KeyStoreLoader - Loading KeyStore at
C:\Users\Z003Z2YP\AppData\Local\Temp\security\example-client.pfx
12:38:37.594 [main] INFO com.company.OpcuaClientRunner - Using
endpoint: opc.tcp://<hostname>:4840 [None] 12:38:37.600 [main] INFO
org.eclipse.milo.opcua.sdk.client.OpcUaClient - Eclipse Milo OPC UA
Stack version: 0.2.3 12:38:37.600 [main] INFO
org.eclipse.milo.opcua.sdk.client.OpcUaClient - Eclipse Milo OPC UA
Client SDK version: 0.2.3 12:38:37.809 [NonceUtilSecureRandom] INFO
org.eclipse.milo.opcua.stack.core.util.NonceUtil - SecureRandom seeded
in 0ms. 12:38:37.815 [ua-netty-event-loop-1] ERROR
org.eclipse.milo.opcua.stack.client.handlers.UaTcpClientMessageHandler
- [remote=<hostname>/<IP>:4840] errorMessage=ErrorMessage{error=StatusCode{name=Bad_ServiceUnsupported,
value=0x800B0000, quality=bad}, reason=null} 12:38:53.828 [main] ERROR
com.company.OpcuaClientRunner - Error running client example:
UaException: status=Bad_Timeout, message=request timed out after
16000ms java.util.concurrent.ExecutionException: UaException:
status=Bad_Timeout, message=request timed out after 16000ms
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at com.company.OpcuaSubscriber.run(OpcuaSubscriber.java:49)
at com.company.OpcuaClientRunner.run(OpcuaClientRunner.java:122)
at com.company.OpcuaSubscriber.main(OpcuaSubscriber.java:120) Caused by:
org.eclipse.milo.opcua.stack.core.UaException: request timed out after
16000ms
at org.eclipse.milo.opcua.stack.client.UaTcpStackClient.lambda$scheduleRequestTimeout$13(UaTcpStackClient.java:326)
at io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:581)
at io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:655)
at io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:367)
at java.lang.Thread.run(Thread.java:748) 12:38:53.828 [main] ERROR
com.company.OpcuaClientRunner - Error running example: UaException:
status=Bad_Timeout, message=request timed out after 16000ms
java.util.concurrent.ExecutionException: UaException:
status=Bad_Timeout, message=request timed out after 16000ms
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at com.company.OpcuaSubscriber.run(OpcuaSubscriber.java:49)
at com.company.OpcuaClientRunner.run(OpcuaClientRunner.java:122)
at com.company.OpcuaSubscriber.main(OpcuaSubscriber.java:120) Caused by:
org.eclipse.milo.opcua.stack.core.UaException: request timed out after
16000ms
at org.eclipse.milo.opcua.stack.client.UaTcpStackClient.lambda$scheduleRequestTimeout$13(UaTcpStackClient.java:326)
at io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:581)
at io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:655)
at io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:367)
at java.lang.Thread.run(Thread.java:748)</pre>
Code to create client in ClientRunner.
private OpcUaClient createClient() throws Exception { File securityTempDir = new File(System.getProperty("java.io.tmpdir"), "security"); if (!securityTempDir.exists() && !securityTempDir.mkdirs()) { throw new Exception("unable to create security dir: " + securityTempDir); } LoggerFactory.getLogger(getClass()) .info("security temp dir: {}", securityTempDir.getAbsolutePath()); KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir); loader.load(); SecurityPolicy securityPolicy = client.getSecurityPolicy(); EndpointDescription[] endpoints; try { endpoints = UaTcpStackClient .getEndpoints(client.getEndpointUrl()) .get(); } catch (Throwable ex) { ex.printStackTrace(); // try the explicit discovery endpoint as well String discoveryUrl = client.getEndpointUrl(); logger.info("Trying explicit discovery URL: {}", discoveryUrl); endpoints = UaTcpStackClient .getEndpoints(discoveryUrl) .get(); } EndpointDescription endpoint = Arrays.stream(endpoints) .filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getSecurityPolicyUri())) .findFirst().orElseThrow(() -> new Exception("no desired endpoints returned")); logger.info("Using endpoint: {} [{}]", endpoint.getEndpointUrl(), securityPolicy); 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) .setIdentityProvider(client.getIdentityProvider()) .setRequestTimeout(uint(5000)) .build(); return new OpcUaClient(config);
Client interface class
public interface OpcuaClientInterface { public static final String USERNAME = "demo"; public static final String PASSWORD = "demo"; default String getEndpointUrl() { return "opc.tcp://localhost:4840/UADiscovery"; } default SecurityPolicy getSecurityPolicy() { return SecurityPolicy.None; } default IdentityProvider getIdentityProvider() { // return new UsernameProvider(USERNAME,PASSWORD); return new AnonymousProvider(); } void run (OpcUaClient client, CompletableFuture future) throws Exception; }
subscriber run implementation
@Override public void run(OpcUaClient client, CompletableFuture future) throws Exception { // synchronous connect client.connect().get(); // create a subscription @ 1000ms UaSubscription subscription = client.getSubscriptionManager().createSubscription(1000.0).get(); List nodeIds = Arrays.asList("SuctionPressure", "DischargePressure", "Flow", "BearingTemperature", "Vibration", "Power"); // List nodeIds = Arrays.asList("DS", "PV"); List MICRs = nodeIds.stream().map(id -> { ReadValueId readValueId = new ReadValueId(new NodeId(3, id), AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE); // important: client handle must be unique per item UInteger clientHandle = uint(clientHandles.getAndIncrement()); MonitoringParameters parameters = new MonitoringParameters(clientHandle, 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); return request; }).collect(Collectors.toList()); // when creating items in MonitoringMode.Reporting this callback is where each // item needs to have its // value/event consumer hooked up. The alternative is to create the item in // sampling mode, hook up the // consumer after the creation call completes, and then change the mode for all // items to reporting. BiConsumer onItemCreated = (item, id) -> item .setValueConsumer(this::onSubscriptionValue); List items = subscription.createMonitoredItems(TimestampsToReturn.Both, MICRs, onItemCreated) .get(); for (UaMonitoredItem item : items) { if (item.getStatusCode().isGood()) { logger.info("item created for nodeId={}", item.getReadValueId().getNodeId()); } else { logger.warn("failed to create item for nodeId={} (status={})", item.getReadValueId().getNodeId(), item.getStatusCode()); } } // let the example run for 5 seconds then terminate // Thread.sleep(1000 * 60 * 1); // future.complete(client); }
I think you may be confused about what a Discovery Server does.
You don't connect "through" a Discovery Server to another server. It's more like a registry where other servers can register themselves and then clients can go and see what servers are available.
The client queries the discovery server for a list of servers, selects one, and then connects directly to that server using the information obtained from the discovery server.