Search code examples
opc-uamilo

How to set the proper data type when writing to an OPC-UA node in Milo?


I am an OPC-UA newbie integrating a non-OPC-UA system to an OPC-UA server using the Milo stack. Part of this includes writing values to Nodes in the OPC-UA server. One of my problems is that values from the other system comes in the form of a Java String and thus needs to be converted to the Node's proper data type. My first brute force proof-of-concept uses the below code in order to create a Variant that I can use to write to the Node (as in the WriteExample.java). The variable value is the Java String containing the data to write, e.g. "123" for an Integer or "32.3" for a Double. The solution now includes hard-coding the "types" from the Identifiers class (org.eclipse.milo.opcua.stack.core, see the switch statement) which is not pretty and I am sure there is a better way to do this? Also, how do I proceed if I want to convert and write "123" to a node that is, for example, UInt64?

       try {
            VariableNode node = client.getAddressSpace().createVariableNode(nodeId);
            Object val = new Object();
            Object identifier = node.getDataType().get().getIdentifier();
            UInteger id = UInteger.valueOf(0);

            if(identifier instanceof UInteger) {
                id = (UInteger) identifier;
            }

            System.out.println("getIdentifier: " + node.getDataType().get().getIdentifier());
            switch (id.intValue()) {
                // Based on the Identifiers class in org.eclipse.milo.opcua.stack.core; 
                case 11: // Double
                    val = Double.valueOf(value);
                    break;
                case 6: //Int32
                    val = Integer.valueOf(value);
                    break;
            }

            DataValue data = new DataValue(new Variant(val),StatusCode.GOOD, null);
            StatusCode status = client.writeValue(nodeId, data).get();
            System.out.println("Wrote DataValue: " + data + " status: " + status);
            returnString = status.toString();
        } catch (Exception e) {
            System.out.println("ERROR: " + e.toString());
        }

I've looked at Kevin's response to this thread: How do I reliably write to a OPC UA server? But I'm still a bit lost... Some small code example would really be helpful.


Solution

  • You're not that far off. Every sizable codebase eventually has one or more "TypeUtilities" classes, and you're going to need one here.

    There's no getting around that fact that you need to be able to map types in your system to OPC UA types and vice versa.

    For unsigned types you'll use the UShort, UInteger, and ULong classes from the org.eclipse.milo.opcua.stack.core.types.builtin.unsigned package. There are convenient static factory methods that make their use a little less verbose:

    UShort us = ushort(foo);
    UInteger ui = uint(foo);
    ULong ul = ulong(foo);
    

    I'll explore that idea of including some kind of type conversion utility for an upcoming release, but even with that, the way OPC UA works you have to know the DataType of a Node to write to it, and in most cases you want to know the ValueRank and ArrayDimensions as well.

    You either know these attribute values a priori, obtain them via some other out of band mechanism, or you read them from the server.