eclipse / milo

Eclipse Milo™ - an open source implementation of OPC UA (IEC 62541).
http://www.eclipse.org/milo
Eclipse Public License 2.0
1.16k stars 431 forks source link

error reading method arguments in Python Server #1329

Closed tbischoff2 closed 4 weeks ago

tbischoff2 commented 4 weeks ago

We have an application with an OPC UA client based on Milo. Now, one of the users had problems with a method in an OPC UA Server based on Python opcua-asyncio: https://github.com/FreeOpcUa/opcua-asyncio It's a method with 1 input and 1 output argument, both of type String (see attached screenshot of UaExpert).

TestOperation

But Milo has problems reading the input and output arguments of the method. To reproduce the problem, I modified the MethodExample2 from the client-examples project of Milo (current version of the master branch), And I also had to modify 2 methods of the "ClientExample" file:

default String getEndpointUrl() {
    return "opc.tcp://localhost:48010";
}

default SecurityPolicy getSecurityPolicy() {
    return SecurityPolicy.None;
}

That's the modified run method of MethodExample2:

@Override
public void run(OpcUaClient client, CompletableFuture<OpcUaClient> future) throws Exception {
    // synchronous connect
    client.connect().get();

    UaObjectNode objectNode = client.getAddressSpace()
        .getObjectNode(new NodeId(2, 1));

    UaMethod testMethod = objectNode.getMethod(new QualifiedName(2, "TestOperation"));
    logArguments(client, testMethod);

    UaMethodNode mn = (UaMethodNode) client.getAddressSpace().getNode(new NodeId(2, 2));
    Argument[] ia = mn.readInputArgumentsAsync().get();

    future.complete(client);
}

The method "logArguments" doesn't find input or output arguments: 09:46:50.929 [main] INFO o.e.m.examples.client.MethodExample2 - Input arguments: none 09:46:50.929 [main] INFO o.e.m.examples.client.MethodExample2 - Output arguments: none

After that, when I call the mehod "readInputArgumentsAsync" an exception occurs (see attachment).

The method of the Python OPC UA Server works normally with other clients or SDKs.

To reproduce the problem, you need Python with the package asyncua: pip install asyncua

After starting the server (python server.py), it's running with this endpoint: opc.tcp://localhost:48010 I also attached the Python file with the OPC UA Server (just rename the "server.txt" to "server.py").

tbischoff2 commented 4 weeks ago

I'm not sure, if attaching the text files worked. So, here is the code of the Python OPC UA Server:

from asyncua import Server, ua import asyncio

async def main(): server = Server() url = "opc.tcp://localhost:48010" await server.init() server.set_endpoint(url) name = "testNamespace" addspace = await server.register_namespace(name)

objects = server.nodes.objects

async def TestOperation(parent, input):
    return [ua.Variant(input.Value, ua.VariantType.String)]

myobj = await objects.add_object(addspace, "MyObject")
input_argument = ua.Argument()
input_argument.Name = "Input"
input_argument.DataType = ua.NodeId(ua.ObjectIds.String)
input_argument.ValueRank = -1
input_argument.ArrayDimensions = []
input_argument.Description = ua.LocalizedText("Input-String")

output_argument = ua.Argument()
output_argument.Name = "Output"
output_argument.DataType = ua.NodeId(ua.ObjectIds.String)
output_argument.ValueRank = -1
output_argument.ArrayDimensions = []
output_argument.Description = ua.LocalizedText("Output-String")

mymethod = await myobj.add_method(addspace, "TestOperation", TestOperation, [input_argument], [output_argument])

await server.start()
print(f"Server started at {url}")
while True:
    await asyncio.sleep(1)

if name == "main": asyncio.run(main())

tbischoff2 commented 4 weeks ago

And the exception:

09:47:13.519 [main] ERROR o.e.m.e.client.ClientExampleRunner - Error running client example: java.lang.ClassCastException: class org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode cannot be cast to class org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode (org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode and org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode are in unnamed module of loader 'app') java.util.concurrent.ExecutionException: java.lang.ClassCastException: class org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode cannot be cast to class org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode (org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode and org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode are in unnamed module of loader 'app') at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396) at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073) at org.eclipse.milo.examples.client.MethodExample2.run(MethodExample2.java:53) at org.eclipse.milo.examples.client.ClientExampleRunner.run(ClientExampleRunner.java:155) at org.eclipse.milo.examples.client.MethodExample2.main(MethodExample2.java:35) Caused by: java.lang.ClassCastException: class org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode cannot be cast to class org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode (org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode and org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode are in unnamed module of loader 'app') at org.eclipse.milo.opcua.sdk.client.nodes.UaNode.lambda$null$15(UaNode.java:1064) at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:684) at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:662) at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2168) at org.eclipse.milo.opcua.sdk.client.nodes.UaNode.lambda$null$16(UaNode.java:1064) at java.base/java.util.Optional.map(Optional.java:260) at org.eclipse.milo.opcua.sdk.client.nodes.UaNode.lambda$null$17(UaNode.java:1061) at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:273) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.Spliterators$ArraySpliterator.tryAdvance(Spliterators.java:1002) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647) at org.eclipse.milo.opcua.sdk.client.nodes.UaNode.lambda$getPropertyNodeAsync$18(UaNode.java:1069) at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150) at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147) at org.eclipse.milo.opcua.stack.client.UaStackClient.lambda$deliverResponse$5(UaStackClient.java:318) at org.eclipse.milo.opcua.stack.core.util.ExecutionQueue$Task.run(ExecutionQueue.java:119) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:840) 09:47:13.524 [ForkJoinPool.commonPool-worker-1] ERROR o.e.m.e.client.ClientExampleRunner - Error running example: java.lang.ClassCastException: class org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode cannot be cast to class org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode (org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode and org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode are in unnamed module of loader 'app') java.util.concurrent.ExecutionException: java.lang.ClassCastException: class org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode cannot be cast to class org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode (org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode and org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode are in unnamed module of loader 'app') at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396) at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073) at org.eclipse.milo.examples.client.MethodExample2.run(MethodExample2.java:53) at org.eclipse.milo.examples.client.ClientExampleRunner.run(ClientExampleRunner.java:155) at org.eclipse.milo.examples.client.MethodExample2.main(MethodExample2.java:35) Caused by: java.lang.ClassCastException: class org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode cannot be cast to class org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode (org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode and org.eclipse.milo.opcua.sdk.client.model.nodes.variables.PropertyTypeNode are in unnamed module of loader 'app') at org.eclipse.milo.opcua.sdk.client.nodes.UaNode.lambda$null$15(UaNode.java:1064) at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:684) at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:662) at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2168) at org.eclipse.milo.opcua.sdk.client.nodes.UaNode.lambda$null$16(UaNode.java:1064) at java.base/java.util.Optional.map(Optional.java:260) at org.eclipse.milo.opcua.sdk.client.nodes.UaNode.lambda$null$17(UaNode.java:1061) at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:273) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.Spliterators$ArraySpliterator.tryAdvance(Spliterators.java:1002) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647) at org.eclipse.milo.opcua.sdk.client.nodes.UaNode.lambda$getPropertyNodeAsync$18(UaNode.java:1069) at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150) at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147) at org.eclipse.milo.opcua.stack.client.UaStackClient.lambda$deliverResponse$5(UaStackClient.java:318) at org.eclipse.milo.opcua.stack.core.util.ExecutionQueue$Task.run(ExecutionQueue.java:119) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:840)

kevinherron commented 4 weeks ago

The getInputArguments, getOutputArguments, etc... methods do not work with FreeOpcUa python implementations because of this bug I reported last year: https://github.com/FreeOpcUa/opcua-asyncio/issues/1529

We've refactored the method call logic in our application so it does not use these accessors and instead does a regular Browse call and searches for the input/output argument property nodes by BrowseName only, and then a regular Read call. It's uglier but works around this bug.

tbischoff2 commented 4 weeks ago

OK, thanks for the information.

kevinherron commented 4 weeks ago

Since I don't think they are ever going to fix this issue I've added a workaround in Milo, at least for this particular case of accessing Property and PropertyNodes via UaNode instances.

The fix will only in the dev/1.0 branch and eventual 1.0 release.