Understanding qualified values

I don't think I understand what's happening when we fill a variable with a system.tag.readBlocking("tagPath") call and I want to.

I'm using the following line of code to fill a variable with a single value rather than the whole qualified value list, but I don't know why it works.

value = system.tag.readBlocking("tagPath")[0].value

Why do we use the .value for the system.tag.readBlocking() function when python lists and dictionaries both use [param] to specify a particular object within them? Why would I not use:

value = system.tag.readBlocking("tagPath")[0]["value"]

While I have a working script because I can copy and paste, I would like to know why the script is working with the current syntax. Thoughts?

I believe the answer here is because the qv is an object ? So, .value is getting the defined "value" attribute of that object. [0] is, of course, the index of the qv object in the read qv list.

3 Likes

Lists use an index, and Dictionaries use a Key.

The system.tag.readBlocking() function returns a List of QaulifiedValue Objects as @amarks has already said.

So in this line:

value = system.tag.readBlocking(['tagPath'])[0].vaule

There are a few things going on. A QualifiedValue object has three attributes, the first and most used is the value, the second the quality, and the third is the timestamp. There are various times when you might want to use any of those attributes.

The object also has 3 getter functions defined that generally take the shape of getValue(). However, because Ignition uses Jython, there is some fancy footwork done in the background that makes it so that most getter and setter functions can be referenced as a "pythonic" attribute, this is why .value works, what is really happening is QualifiedValue.getValue().

So, the call to readBlocking() returns a list of QualifiedValues and [0] dereferences the list to the object at index 0, and .value returns the value of the value attribute of the QualifiedValue.

Your next question might be "Why does it return a list when I'm only reading a single tag?". Well, even though you can provide a single string to the function, it was actually designed to and takes a List of tag paths. This is an important feature because reading 2 or more calls in a single call to readBlocking() is more performant than calling the function multiple times. The larger the number of tags you read at once the greater this performance enhancement becomes. (The same goes for system.tag.writeBlocking().

The returned list of QualifiedValues is guaranteed to match the order of the tag paths provided, so the QualifiedValue at Index 0 will always be the value for the tag path at index 0.

This allows you to do things like this:

tagPaths = ['tagPath1','tagPath2',....'tagPathN']
tagValues = {path:qv.value for path,qv in zip(tagPaths,system.tag.readBlocking(tagPaths)}

tagValues['tagPath1'] = 'value of tag path 1'
tagValues['tagPath2'] = 'value of tag path 2'
....
tagValues['tagPathN'] = 'value of tag path N'

Hopefully that provides a little bit of insight into what is going on.

3 Likes

Louis is correct here with this writeup, and if you are curious where to find sources for this info:

All Ignition scripting function in the User Manual will link to any Ignition specific objects they use, typically in the "Returns" section. Such as: system.tag.readBlocking | Ignition User Manual

Which references: Scripting Object Reference | Ignition User Manual and the qualified value object.

1 Like

THAT is what I was looking for. Thank you for the thorough response and depth of insight.