Ignition 7.9.2 - Writing to OPC Array

Is it possible to write to elements in a OPC Array?
I think I tried this, when Ignition 7.9.0 was released, and I believe it worked (correct me if I’m wrong).
I’m currently just trying to write to a “test” array defined in Kepware OPC server, but I’m only getting the following error message:

Yeah, I just had problems with that. My OPC UA server is on a CoDeSys 3 PLC (Mine is WAGO, but there are other that use the same thing, like Bedrock)

Things that did not work:
Dragging the tag from OPC into Ignition: Results in a String that shows the values (if they are simple enough), but does not allow writing to it.
Creating an array tag of matching type that points to the OPC array. Again, shows values but does not allow writing to it.

Solution that did work:
Creating a separate tag for each element in the array. Point that element to “Path\ArrayTag[x]” where x is the index.

This works with structures in the PLC too:
On the PLC create a non arrayed structure of the type that you are going to have in the array. Drag it into Ignition.
Use that structure to create a UDT and replace all the addresses with indirect addresses using a UDT parameter.
Then use “Path\ArrayTag[x]” as the parameter to point UDT instances to the right item.

Despite the last minute introduction of an array tag type, I think the best thing to do for now is pretend it doesn’t exist and address elements of an array directly just as was required in the past.

Arrays will get a first class treatment in the next major release.

That is a nice solution, Caleb. Unfortunately I wasn’t able to get that to work (or, I was misunderstanding the solution…very possible!:grin:). I’d like to expand on your solution and see if this approach is of assistance to anybody:

  1. In the PLC, build a DUT Structure of the data type(s) that you want in your array – even if it’s only one word.
  2. In the PLC, declare the variable as an array of that structure. Ex.: mMOPosVel:ARRAY [1…5] OF sPosVlcty; Where “sPosVlcty” is the DUT Structure.
  3. That’s it! You’re done. Now you can restart the OPC server (an unfortunate necessary step) and then drag your arrays into Ignition and start reading/writing to them.

It is apparent that Ignition will recognize an array of Codesys DUT’s, but not an array of the actual word variables.
See below pics for reference:

Referring the array elements one by one ends up generating a lot of write commands. At least, this is what I'm seeing working with the Modbus KEP OPC Server. If I build a tags list for the OPC write values command, the server process them one by one. If I use the OPC write value command and the right type array of values, it writes them all in one command.

The problem is that I'm not able to create the right type array. I can see that I'm not the only one.

Maybe you can clarify it to me. It seems that the Python array class is not fully implemented. It's there but it's not doing what it's supossed to do.

When I read from the OPC server

lstQValues = system.opc.readValue("KepServer", "ns=2;s=Channel.Device.DataArray")
print lstQValues.value
array(java.lang.short, [101, 202, 303, 404,...

I get a short array but most properties and methods are not implemented. But the array class

I tried to get the type code to use it to produce an array of the same type.

print lstQValues.ArrayType
print lstQValues.typecode

both commands fail.

When I try to create the array

from array import array
lstWrtValues = array('i', [1,2,3,4,5,6,7])
print lstWrtValues

I get something that looks like it but it's not recognized by the OPC server as a short array.

array('i', [1, 2, 3, 4,...

When I write using it

system.opc.writeValue("KepServer", "ns=2;s=Channel.Device.DataArray", lstWrtValues)

I get a Bad_TypeMismath error.
I tried other integer types, 'I', 'h', 'H', all of them fail. The weird thing is that the array class seems to work, at least parts of it. Method count works, append works, reverse doesn't seem to do anything. It's like the typecode is ignored and the array ends up being a regular list.

One workaround I found is to use the same array I get from the OPC server, populate it and send it back.

lstQValues = system.opc.readValue("KepServer", "ns=2;s=Channel.Device.DataArray")
lstWrtValues = lstQValues.value
lstWrtValues[0] = 1
lstWrtValues[1] = 2
lstWrtValues[2] = 3
lstWrtValues[3] = 4
lstWrtValues[4] = 5
system.opc.writeValue("KepServer", "ns=2;s=Channel.Device.DataArray", lstWrtValues)

It works and it does the right thing, all registers get written in one function 16 command. But it makes no sense. I should be able to create the array I need.

The change you mention for the next major release includes a full implementation of the array class?

What version are you using @gkawaguchi? Using a list for the write works in 7.9.3, at least for an array of Int16 values.

7.8.3

Are you sure it works? With the KEP server?

I don’t have this issue with the Ignition Modbus driver because I can’t use arays with it anyway. But lists and the writeValues, referring tags individually, works fine. The driver is smart enough to put it all together. The problem with KEP is that I’m using a tag array, not an array of tags, and the data type of the value doesn’t match when I write to it.

I can try upgrading, it’s a testing installation. But I’d prefer not to make changes in the middle of the project unless I really have to.

I don’t know if it works with KEPServer, I tested with something else. But the “improved” array support we currently have wasn’t implemented until 7.9.

The “first-class” support I mentioned earlier in this thread is for 8.0.

I'm trying 7.9 now.

The array class is still unreliable. I think there's a conflict of names and classes.

from array import array
lstArray = array('i', [1,2,3,4,5])
print lstArray
array('i', [1, 2, ...
lstQValues = system.opc.readValue('KepServer', 'ns=2;s=Channel.Device.DataArray')
print lstQValues.value
array(java.lang.short, [101, 202, ...

They're both arrays but they're different somehow.

print lstArray.typecode
i
print lstArray.itemsize
4
print lstQValues.value.typecode
AttributeError: 'array.array' object has no attribute 'typecode'
print lstQValues.value.itemsize
0

Despite the same name, they seem to be different classes with different methods and properties.

But it works and it's a lot better thatn the workaround I was using. So I'm upgrading this project to 7.9.
I'm surprised to see that it works regardless of the typecode, itemsize or even data type. Even the float and double array work when the function calls for a short array. I'm not complaining but I don't feel comfortable passing a parameter of the wrong type through OPC. That's why I didn't even try the list because it's an ambiguous structure. By the way, I tried with a list and it works too.

Thanks for your help, Kevin.

Our UA client implementation is taking care of coercing values to the right type before writing, if possible. I think feeling uneasy about that is actually the right intuition to have, but unfortunately it’s just not possible to create all the UA datatypes from scripting.

The array class is part of Jython. We’re upgrading to Jython 2.7 in Ignition 8; maybe it’s better there.

I’d avoid it and just use a list.

I’ll give it a try. I have to accept that you know more about how the client works than I do. Besides, if it’s going through coercion either way, it doesn’t make any difference to use the right type array…

I’m still confused with the Jython implementation. But it’s something for another post.

Just talking about the array thing, according the the Jython documentation, the syntax is array(sequence, type). Ignition uses array(type{, sequence}), Python style. Jython doesn’t mention any other properties or methods. Ignition seems to be more like Python in that sense, even when not fully compliant.
My first reference is always the Python documentation, even when not 100% accurate. Working from Jython documentation is useless most of the time.

Jython’s jarray module isn’t present in its current documentation, but is unchanged from v2.1, shown here. I tend to poke around in the source when in doubt.

pturmel, it is in the current documentation. At least what I think it’s the current documentation.

Here, http://www.jython.org/docs/reference/indexprogress.html
The Jython Book seems to be the most complete and updated documentation. Your link is an archived 2.1 version. The Jython Book covers the current 2.5 version.

Still confusing. Maybe I’m too old school but I feel lost trying to code without a reliable language reference. I do it anyway and, so far, it seems to work well. It’s just that it doesn’t feel right and it takes more time.

Will the ”first-class” support for arrays make it into Ignition 8?

To me that means our drivers all support arrays too, and that’s not happening for 8. I’ll have to look into what the current state of arrays are in the tag system and if anything is changing.

Ok. To me it’s enough if it works with external OPC UA servers (specifically Siemens S7-1500).

When will a summary of the new OPC UA features in 8.0 be revealed?

Can you summarize what array support means to you? I need to tease apart what is OPC UA and what’s improvements to the tag system.

When an OPC UA array corresponds to a single tag in Ignition, these two are interconnected using a single OPC UA item path and the whole array could be written to in a single write operation.

This already works now, from scripting. The issue we have now is that modifying individual elements of the array from UI doesn’t work, and even when it does get fixed it’ll be dependent on the UA server supporting writes using the index range parameter.

A post was split to a new topic: Writing to OPC StringArray Tag