Writing to PLC UDTs - Siemens OPC-UA and jsonSet - "Bad_EncodingError"

Hi -
I'm testing reading / writing to OPC-UA on my S7-1500 PLC using the Derived Tags and jsonGet / jsonSet (per methods outlined in the manual and elsewhere on this forum).

I managed to get a jsonGet working properly.
When I test writing to the same tag I receive a "Bad_EncodingError" message:
Error writing to HasAlarms.value: Bad("Bad_EncodingError: Encoding halted because of invalid data in the objects being serialized.")
image

This appears to be an issue similar to the one encountered in this thread.

I have confirmed:

  • Data is writable via UAExpert
  • Data members are set to writable via OPC-UA in the Siemens PLC.

Here is the configuration I am working with.

  • Trying to access a boolean member (bHAsAlarms) of a UDT. UDT is an array of the UDT, and the atomic data types are organized into STRUCTs under the main UDT.
    image
  • I have defined an OPC tag, pointing to the entire array "CM_Pressure" as Document data type.
    o This has an OPC Path of:
    nsu=http://www.siemens.com/simatic-s7-opcua;s="dbInterfaces"."CM_Pressure"
  • I have defined a Reference Tag called Source, which points to CM_Pressure (the Ignition OPC tag), also as a Document Type.
  • I have defined a Derived Tag called "HasAlarms" which has the following jsonSet and jsonGet expressions:
    o jsonGet({source},"[1].CFG.bHasAlarms")
    o jsonSet({source},"[1].CFG.bHasAlarms",{value})
    image

When I toggle the bit from any other source, the derived tag updates as expected. However, when trying to write using the derived tag, I get the Bad_EncodingError. Is there some caveat or constraint I am missing with these JSON expressions? I have a feeling it has to do with the JSON string.

Thanks.

Can you share the full UDT definitions from TIA?

When you test with UAExpert are you writing the whole structure or just to one of the member nodes?

Hah, this appears to be a rather simple fix, although with some implications to the number of tags that need to be configured in Ignition. Apparently the jsonSet and jsonGet expressions do not like arrays of UDTs (I have not tried this with arrays of atomic data types).

For example:
Setting the Source tag to point to a OPC tag with:
nsu=http://www.siemens.com/simatic-s7-opcua;s="dbInterfaces"."CM_Pressure"
does not work because the Derived Tag needs to include the element in the JSON expression:
jsonSet({source},"[1].CFG.bHasAlarms",{value} <--- does not like "[1]"

Alternatively, setting the OPC Tag directly to the array member like this:
nsu=http://www.siemens.com/simatic-s7-opcua;s="dbInterfaces"."CM_Pressure"[1]
results in a Derived Tag like this:
jsonSet({source},".CFG.bHasAlarms",{value} <--- this works!

So this requires an Ignition tag for each element, and I can't use a tag for the whole array structure.
Interestingly, the fully qualified OPC Path to the actual tag is:
"dbInterfaces"."CM_Pressure"[1]."CFG"."bHasAlarms"

Notice that the array element [1] is outside of the quotation marks. I'm not sure if this is what is causing an issue with the JSON string (just a suspicion) or it is some other constraint on how JSON works.

What version of Ignition are you using? Support for writing to a Document tag representing an array of structures looks like something that was implemented in 8.1.27.

Wrote my response before I saw your reply:

Full UDT in TIAPortal looks like this - it's a highly modified version of DMC's Siemens Open Library.


In UA Expert I was just writing to the individual "bHasAlarms" member to make sure I did not have some type of write protection set inadvertently and to rule out an issue with the PLC or the OPC-UA configuration.

image

8.1.24. I'll try upgrading.

Ok, just know this is a very different test. When you set up these nested hierarchies of JSON and jsonSet/jsonGet the writes all percolate up into a write of the entire structure (or structure array in this case), not a write to the individual Node representing that member in the address space.

Not all servers expose structure members as individual Nodes in the address space. Siemens does, but you can't actually use any serious quantity of them without overloading the PLC's comms.

This just begs for a variant of a derived tag that can write back to a configurable OPC Item Path instead of writing through the {source}. Might not work for other servers, but I bet that would be fabulous for Siemens.

Edit: Heck, that would be super valuable with my EtherNet/IP driver too, to allow use of consumed tags with an alternate writeback path.

1 Like

That's just an expression tag with a tag change script... which we sort of used to have with the "OPC write back".

To really be useful the target would need to be parameterized or otherwise allow you to try to derive from context. Hmm

edit: err, not an expression tag. Umm...

I'm thinking a generic facility exposing tag properties like WriteOPCServer and WriteOPCItemPath OPCWriteServer and OPCWriteItemPath. (Better for leading lowercase like the existing opcServer and opcItemPath in JSON.) Those would certainly be parameterizable in the usual way. Via UDTs (anyone not using a UDT for this deserves their misery).

Well, there's probably an idea there. I slept very little last night so I'm probably going to be useless today.

Well, I now want to make a tag provider that extends the standard realtime tag provider to offer this.

Hmmm. Will investigate. Eventually. But please do this first party :grin:

Good to know.
So when I write to my "bHasAlarms" member, I am actually writing to the entire array element / structure (in this case, CM_Pressure[1])?

If yes, I would think writing to the individual node (bHasAlarms) would be more efficient than writing to the entire structure in one go, right? Or is the issue more that by NOT using the jsonGet/Set methods you are forced to subscribe to the individual tags / nodes, thus overloading comms?

Sorry if I am misunderstanding something here.

When set up like this with jsonGet/jsonSet, yes.

Yes, more efficient. But...

Bingo. Would be nice if you could just skip all this setup and bring each individual tag in, but at least with Siemens you can't unless you don't need that many tags.

1 Like

If this is the case, it may be better to pull in each UDT element (CM_Pressure[1]) vs. (CM_Pressure) since I won't be writing to the entire structure when I need to make updates.

I have other UDT types like this but are 60 elements long.

1 Like

Yeah, that might be worth the extra setup. Certainly better to write a single CM_Pressure structure instead of the entire array of structures.

2 Likes

Hello, I'm late but I find this very instructive and wonder if there is a way to write to the source tag whith one shot from a script if we can not write to multiple tag attache to this source tag?