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.")
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.
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})
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.
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.
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.
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.
I'm thinking a generic facility exposing tag properties like WriteOPCServer and WriteOPCItemPathOPCWriteServer and OPCWriteItemPath. (Better for leading lowercase like the existingopcServerandopcItemPathin JSON.) Those would certainly be parameterizable in the usual way. Via UDTs (anyone not using a UDT for this deserves their misery).
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?
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.
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.
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?