Error when writing to chained derived Siemens OPC document tag but works with memory document tag

A colleague is trying to use a Siemens PLC via onboard OPC-UA to read a nested UDT within a datablock. He’s reading the top level datablock in as a Document tag and then using a derived tag with jsonGet to read the nested UDT, then a derived integer tag with jsonGet to read a key from this tag. Essentially it’s doing jsonGet(jsonGet({source}, "Seq"), "Command").
Example tag JSON below which is in the format:
base tag = opc tag, the root datablock tag
seq tag = get “Seq” object from base tag
cmd tag = get “Command” integer tag from seq tag (essentially, get Seq.Command from base tag)

When trying to write to the cmd tag, he’s seeing this error:
image

INFO   | jvm 1    | 2022/08/11 15:58:20 | W [o.e.m.o.s.c.s.OpcUaBinaryStreamEncoder] [05:58:19]: Not a built-in type: class com.inductiveautomation.ignition.common.document.Document 
INFO   | jvm 1    | 2022/08/11 15:58:20 | E [o.e.m.o.s.c.t.u.UascClientMessageHandler] [05:58:19]: Error serializing WriteRequest(requestHeader=RequestHeader(authenticationToken=NodeId{ns=0, id=217572643}, timestamp=DateTime{utcTime=133046710999830000, javaDate=Thu Aug 11 15:58:19 AEST 2022}, requestHandle=6617, returnDiagnostics=0, auditEntryId=null, timeoutHint=60000, additionalHeader=null), nodesToWrite=[WriteValue(nodeId=NodeId{ns=3, id="SQ110_WM5"."SQ110_WM5"}, attributeId=13, indexRange=null, value=DataValue{value=Variant{value={
INFO   | jvm 1    | 2022/08/11 15:58:20 |     "Seq":{\n "\"Command\": 30\n}"
INFO   | jvm 1    | 2022/08/11 15:58:20 | }}, status=null})]): unknown builtin type: -1 
INFO   | jvm 1    | 2022/08/11 15:58:20 | org.eclipse.milo.opcua.stack.core.UaSerializationException: unknown builtin type: -1
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeBuiltinType(OpcUaBinaryStreamEncoder.java:736)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeValue(OpcUaBinaryStreamEncoder.java:654)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeVariant(OpcUaBinaryStreamEncoder.java:637)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeDataValue(OpcUaBinaryStreamEncoder.java:323)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeDataValue(OpcUaBinaryStreamEncoder.java:879)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.types.structured.WriteValue$Codec.encode(WriteValue.java:106)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.types.structured.WriteValue$Codec.encode(WriteValue.java:86)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec$GenericBinaryDataTypeCodec.encode(GenericDataTypeCodec.java:54)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeStruct(OpcUaBinaryStreamEncoder.java:941)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.lambda$writeStructArray$3(OpcUaBinaryStreamEncoder.java:1107)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeArray(OpcUaBinaryStreamEncoder.java:83)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeStructArray(OpcUaBinaryStreamEncoder.java:1107)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeStructArray(OpcUaBinaryStreamEncoder.java:1123)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.types.structured.WriteRequest$Codec.encode(WriteRequest.java:85)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.types.structured.WriteRequest$Codec.encode(WriteRequest.java:69)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec$GenericBinaryDataTypeCodec.encode(GenericDataTypeCodec.java:54)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder.writeMessage(OpcUaBinaryStreamEncoder.java:918)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.client.transport.uasc.UascClientMessageHandler.lambda$encode$9(UascClientMessageHandler.java:334)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.channel.SerializationQueue.lambda$encode$0(SerializationQueue.java:52)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at org.eclipse.milo.opcua.stack.core.util.ExecutionQueue$Task.run(ExecutionQueue.java:119)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
INFO   | jvm 1    | 2022/08/11 15:58:20 |   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

If he converts the base opc tag into a memory tag and writes the same document object to the memory tag, then the write to the cmd tag works fine.

JSON for the OPC tag and derived tags where the cmd tag write fails:

{
  "tags": [
    {
  "valueSource": "memory",
  "opcItemPath": "nsu\u003dhttp://www.siemens.com/simatic-s7-opcua;s\u003d\"SQ110_WM5\".\"SQ110_WM5\"",
  "dataType": "Document",
  "name": "base",
  "value": {
    "Seq": {
      "Command": 5
  },
  "tagType": "AtomicTag",
  "opcServer": "BBD_PLC2"
},
    {
      "valueSource": "derived",
      "deriveExpressionGetter": "jsonGet({source}, \u0027Command\u0027)",
      "dataType": "Int4",
      "deriveExpressionSetter": "jsonSet({source}, \"Command\", {value})",
      "sourceTagPath": "[.]seq",
      "name": "cmd",
      "tagType": "AtomicTag"
    },
    {
      "valueSource": "derived",
      "deriveExpressionGetter": "jsonGet({source}, \u0027Seq\u0027)",
      "dataType": "Document",
      "deriveExpressionSetter": "jsonSet({source}, \"Seq\", {value})",
      "sourceTagPath": "[.]base",
      "name": "seq",
      "tagType": "AtomicTag"
    }
  ]
}

JSON for the memory tag + derived tags where the cmd tag writes successfully

{
  "tags": [
    {
      "valueSource": "memory",
      "dataType": "Document",
      "name": "base",
      "value": {
        "Seq": "{\n    \"Command\": 8}"
      },
      "tagType": "AtomicTag"
    },
    {
      "valueSource": "derived",
      "deriveExpressionGetter": "jsonGet({source}, \u0027Command\u0027)",
      "dataType": "Int4",
      "deriveExpressionSetter": "jsonSet({source}, \"Command\", {value})",
      "sourceTagPath": "[.]seq",
      "name": "cmd",
      "tagType": "AtomicTag"
    },
    {
      "valueSource": "derived",
      "deriveExpressionGetter": "jsonGet({source}, \u0027Seq\u0027)",
      "dataType": "Document",
      "deriveExpressionSetter": "jsonSet({source}, \"Seq\", {value})",
      "sourceTagPath": "[.]base",
      "name": "seq",
      "tagType": "AtomicTag"
    }
  ]
}

Does jsonGet({source}, "Seq.Command") work?

1 Like

The problem is that this is the value that ends up at the OPC client layer, which isn't complete and can't be turned into a struct.

I can't tell if you omitted other members for the sake of the example or if they don't exist, but you have to fully define every member of both the host and nested types with derived tags and json get/set if you're going to be writing to any of the tags. When we write to a structure, we have to write the whole structure, and this derived tag scheme can't assemble the whole structure unless you've defined all of the tags.

This works! or rather, the write version works (the read was already working). Thanks :smiley:

jsonSet({source}, "Seq.Command", {value})

Correct, I reduced (or tried to) the structure to simplify my example and may have stuffed it up :slight_smile: ; the actual structure has a lot more tags.

I came across this post in a hunt for a solution that's very similar to this post. Only in my case the value is nested in one more structure.
This expression fails with "Bad_EndcodingError:..." :
jsonSet({source}, "ProcessResults.CNC.MachiningCenter", {value})

But if I hard code the value to 10 it will write 10 when the tag is modified
jsonSet({source}, "ProcessResults.CNC.MachiningCenter", 10)

Any thoughts in what I maybe missing here?

:crazy_face: my bad… Tag Data Type was set to “string”, when I set it correctly to “integer” the {value} works