# How to locate the number 'value' of a Tag's Data Quality

**URL:** <https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840>\
**Category:** Ignition\
**Created:** [July 24, 2019, 5:13pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840 "2019-07-24T17:13:21Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![byrnep](https://avatars.discourse-cdn.com/v4/letter/b/db5fbb/32.png) [@byrnep](https://forum.inductiveautomation.com/u/byrnep)\
**Post date:** [July 24, 2019, 5:13pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/1 "2019-07-24T17:13:21Z")

</div>

[https://docs.inductiveautomation.com/display/DOC79/Tag+Quality+and+Overlays](https://docs.inductiveautomation.com/display/DOC79/Tag+Quality+and+Overlays)

Says that :

The following table outlines the primary data qualities. The most important is **Good** , and that has a value of **192**. There are more values, but these represent the most common:

We are currently working to correct a problem in our network introduced by our security team segmenting the network. The Ignition computer is able to reach out to a PLC via Kepware, and displays points that are monitored from the PLC , however, when the tags are created, they are created with Bad Quality.

It might help things if I could find out exactly what the ‘value’ is (as listed on the table in the linked page) but I don’t seem to be able to find it. Any help?

Answered:

The table is incomplete. ‘Bad Quality’ (among who knows what else) is not a quality that appears on the table of qualities. It ought to but does not. ‘Bad Quality’ represents a tag that is experiencing an unknown error. If your error can be diagnosed, you might get lucky and get a value that appears on the table, which will assist with troubleshooting. That’s why you’d be looking at a tag’s quality.

---

<div class="post-metadata">

**Author:** ![bpreston](https://avatars.discourse-cdn.com/v4/letter/b/4af34b/32.png) [@bpreston](https://forum.inductiveautomation.com/u/bpreston)\
**Post date:** [July 24, 2019, 5:52pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/2 "2019-07-24T17:52:43Z")

</div>

Where are trying to look for the quality value?

If you drill into the tag in the tag browser of the designer it shows Quality in there but gives you a string to tell you the quality.

If you are in an expression you can put in the tag path followed by .quality to bring the quality number into an expression.

If you are in a script when you do system.tag.read(“tagpath”).quality will return the quality number of the tag.

---

<div class="post-metadata">

**Author:** ![byrnep](https://avatars.discourse-cdn.com/v4/letter/b/db5fbb/32.png) [@byrnep](https://forum.inductiveautomation.com/u/byrnep)\
**Post date:** [July 24, 2019, 6:12pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/3 "2019-07-24T18:12:46Z")

</div>

Hi,

So, the exact code I’m using in the script console is here:

```auto
print(system.tag.read("Cryo/ADPFlowMeter").quality)
print(system.tag.read("Cryo/ADPFlowMeter.Quality"))

```

And it returns:

```auto
Bad Quality
[Bad Quality, Good, Wed Jul 24 11:12:05 PDT 2019]
>>>

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 24, 2019, 7:54pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/4 "2019-07-24T19:54:06Z")

</div>

> [@byrnep](#):
>
> It might help things if I could find out exactly what the ‘value’ is (as listed on the table in the linked page) but I don’t seem to be able to find it. Any help?

Why? Genuine question; the integer codes used are basically arbitrary. If you want to know what they mean, then the human-readable representation you get by string-converting a qualified value or quality object is good enough. If, instead, you're trying to drive logic, you _absolutely should not_ care about specific quality codes - instead, use the quality member's `isGood()` method, or the dedicated `isGood()` expression function; eg:  
`if system.tag.read("path/to/myTag").quality.isGood():`  
`isGood({path/to/myTag})`

[https://docs.inductiveautomation.com/display/DOC80/isGood](https://docs.inductiveautomation.com/display/DOC80/isGood)

---

<div class="post-metadata">

**Author:** ![byrnep](https://avatars.discourse-cdn.com/v4/letter/b/db5fbb/32.png) [@byrnep](https://forum.inductiveautomation.com/u/byrnep)\
**Post date:** [July 24, 2019, 8:47pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/5 "2019-07-24T20:47:39Z")

</div>

The lack of a ‘Bad Quality’ entry in the table in the documentation has me thinking that ‘Bad Quality’ doesn’t correspond to any of the integer codes, and is a general ‘bad state’. The fact that integer codes are given in the documentation leads me to believe they are both accessible and useful to the user. I have a communication problem, but I have not managed to figure out its parameters. If I could get a code, that would be a start as to where to begin looking/who to call for help. One of these assumptions is apparently wrong, but I don’t know what.

I string converted a qv, and got nothing, since it’s a list in python, I’m not sure what I should have expected.

```auto
print(str(system.tag.read("Cryo/ADPFlowMeter")))
'[0.0, Good, Wed Jul 24 12:00:34 PDT 2019]'

```

I’m not trying to drive logic. I have a network issue between my PLC and my ignition gateway that is interfering with communication, and I’d like Ignition to tell me anything it can about how the info is or isn’t coming in.

The codes may be arbitrary, but they each correspond to a specific problem with the link, which could be debugged, correct?

I don’t care if isGood. I know isBad. I want howIsBad. Ignition has codes for that, I’d like to know how to access them, or to know why they are in the public documentation?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 24, 2019, 9:19pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/6 "2019-07-24T21:19:54Z")

</div>

> [@byrnep](#):
>
> '[0.0, Good, Wed Jul 24 12:00:34 PDT 2019]'

That's not a list - that _is_ the string representation of the Qualified Value object. 0.0 is the value, 'Good' is the quality, and the last is the timestamp of that value.  
Codes used specific integer values in 7.9 for compatibility reasons across Vision (in the backend, 8.0 uses an entirely different mechanism that's mostly compatible). In all cases, casting to string should give you as much level information as the system has...which is not much. The most common codes (for 7.9) are listed here:  
[https://docs.inductiveautomation.com/display/DOC79/Tag+Quality+and+Overlays#TagQualityandOverlays-PrimaryDataQualities](https://docs.inductiveautomation.com/display/DOC79/Tag+Quality+and+Overlays#TagQualityandOverlays-PrimaryDataQualities)

It's in the manual because it _can_ be relevant, it just isn't in 99% of situations. Also, the `isGood` expression function is pretty new, so there's lots of older code that relies on direct integer comparisons...which caused a lot of problems when people upgraded from 7.9 to 8.0 and there was an issue with the new quality codes used.

---

<div class="post-metadata">

**Author:** ![byrnep](https://avatars.discourse-cdn.com/v4/letter/b/db5fbb/32.png) [@byrnep](https://forum.inductiveautomation.com/u/byrnep)\
**Post date:** [July 25, 2019, 12:16am UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/7 "2019-07-25T00:16:16Z")

</div>

Right.

Except the string I was getting, on the table you linked to, which I had also linked to at the top of this page, after having read it, was not on that table. There’s a fundamental disconnect in the information there. You get that right? If there’s a table telling me ‘These are the strings and values’ and I’m not getting a string from that table, I have to assume it’s not to be referenced in the table.

‘Bad Quality’ provides no more information than I should already have by the time I’m checking the quality. It’s useless. Tautological.

Expression\_Eval\_Error 310   
The expression in the tag generated an error during execution. The error log should provide more information on the error.

This is a useful error code and string and explanation. It tells me what is up and where to go to begin solving the problem.

I’m going to do my best to sum up what I _think_ the answer is, but no one seems to be at all sheepish or embarrassed about giving it so I’m not sure I’m getting it. (I would be):

There are a number of codes. There’s a table of codes. It’s existence implies it should be consulted.  
The table is incomplete. A very common result is not in the table. The very common result does not provide any information that is not provided by the tag not working.

I got the very common result, which could be made more informative simply along the lines of ‘unknown error’ and spent the day on a wild goose chase trying to reference it off an incomplete table based on an assumption that information provided in a manual would be complete, and got a wild goose chase with people telling me to typecast a string I’d already pulled and pasted into a string and to consult a table I’d already consulted?

‘Bad Quality’ is a part of the table, but is not listed. It has a value, but no qualities’ value can be found outside the table, which this one does not appear on. Unlike most all other entries in the table, it does not provide any more granular information and if a tag’s quality is ‘bad quality’ it is on the user to locate the error because it’s outside Ignition’s diagnostic capability, yes?

If I seem frustrated it’s because I am. That penultimate paragraph could have been given and saved everyone time.

---

<div class="post-metadata">

**Author:** ![paul.mangels](https://avatars.discourse-cdn.com/v4/letter/p/a698b9/32.png) [@paul.mangels](https://forum.inductiveautomation.com/u/paul.mangels)\
**Post date:** [September 4, 2020, 3:53pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/8 "2020-09-04T15:53:50Z")

</div>

As a follow up to this, I am currently running into an issue where `system.tag.read("TagPath").quality` returns “Good” as a string instead of 192 as an integer when I call it in the script console. I’m running v8.0.15. In general, there is not a lot of clarity in the documentation on when to expect a string vs an integer, and I would generally prefer to do integer compares vs relying on magic strings to check tag quality.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 4, 2020, 4:12pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/9 "2020-09-04T16:12:47Z")

</div>

You shouldn’t use string comparison _or_ integer comparison. In the vast majority of cases, it’s preferable to use the dedicated methods on [`QualityCode`](http://files.inductiveautomation.com/sdk/javadoc/ignition80/8.0.14/com/inductiveautomation/ignition/common/model/values/QualityCode.html#isGood()) - `isGood()`, `isBad()`, etc directly:

`system.tag.read("TagPath").quality.isGood()`  
Or, thanks to Jython:  
`system.tag.read("TagPath").quality.good`

If you actually need to check for a specific quality code, then you should use `is` against a static member of the `QualityCode` class:

```python
from com.inductiveautomation.ignition.common.model.values import QualityCode
system.tag.read("TagPath").quality.is(QualityCode.Bad_Failure)

```

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [September 6, 2020, 12:55pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/10 "2020-09-06T12:55:51Z")

</div>

It would be nice if there was an ‘exists’ method to check if the quality is ‘not found’, unless there already is something to do this? I use this a lot with templates to check if certain tags exist for the particular device so I can make more generic templates

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 8, 2020, 2:47pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/11 "2020-09-08T14:47:51Z")

</div>

Use `is` with the `Bad_NotFound` static constant:

```auto
QualityCode.Bad_NotFound

```

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [September 8, 2020, 4:37pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/12 "2020-09-08T16:37:04Z")

</div>

Cheers. Is there something similar for the expression language?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 8, 2020, 4:53pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/13 "2020-09-08T16:53:00Z")

</div>

Not outside the `isGood()` function…  
Thinking about it, I’m not sure there is a good way to do it for expressions that won’t end up with the same ‘magic strings’ problem. I’ll file a ticket and see what we can come up with.

---

<div class="post-metadata">

**Author:** ![justin.brzozoski](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justin.brzozoski/32/13452_2.png) [@justin.brzozoski](https://forum.inductiveautomation.com/u/justin.brzozoski)\
**Post date:** [October 15, 2020, 6:06pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/14 "2020-10-15T18:06:18Z")

</div>

I’m not sure if this has been added to the SDK since this thread was started, but the QualityCode object now has a `getCode` method that returns the integer value.

You can do things like this in the scripting console:

```auto
>>> from com.inductiveautomation.ignition.common.model.values import QualityCode
>>> QualityCode.Error_TimeoutExpired.getCode()
-1073741049
>>> QualityCode.Error_Exception.getCode()
-1073741048

```

Very handy to us as developers of a custom SparkPlug edge device since we can only push quality codes in integer form and want them to be meaningful in Ignition.

---

<div class="post-metadata">

**Author:** ![witman](https://avatars.discourse-cdn.com/v4/letter/w/d2c977/32.png) [@witman](https://forum.inductiveautomation.com/u/witman)\
**Post date:** [November 18, 2020, 10:46pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/15 "2020-11-18T22:46:51Z")

</div>

In addition to an expression for tag exists, an expression for isDisabled would be great. We use the same UDTs on a lot of different ancient and modern PLCs (thank you for tag property overrides and scripted tag creation!) and disable unused UDT members that don’t exist in the older PLCs. Templates adapt based on whether members are disabled or not. Unfortunately we seem to be stuck with magic strings to make this happen.

Alternatively, we could use the isGood expression if it weren’t for the fact that disabling quality overlays on internal template properties bound with indirect tag bindings using a tagPath template parameter causes the isGood expression to evaluate to true on those template properties regardless of the quality of the binding. This means we can’t use isGood without showing bad quality overlays for disabled features (disabled via disabled UDT members). Is this a bug or intended behavior (observed in Vision 8.0.16)?

Either way, exists() and isDisabled() tag quality expressions would be useful. Or maybe something like isEnabled() could tell us it both exists and is enabled–would be perfect for our use case.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [August 13, 2021, 4:00pm UTC](https://forum.inductiveautomation.com/t/how-to-locate-the-number-value-of-a-tags-data-quality/26840/16 "2021-08-13T16:00:28Z")

</div>

Reviving this thread because of changes that landed in the latest nightly build/8.1.10:

> [@Nightly 8.1 Changelogs - 2021](https://forum.inductiveautomation.com/t/nightly-8-1-changelogs-2021/42410/137):
>
> Nightly Changelog: 8.1.10-b20210813 Platform 3512: Old MySQL drivers prevent Gateway startup if using alarm journal profile An old installed MySQL JDBC driver (prior to v5.1.0) no longer prevents the Gateway from fully starting when having an alarm journal configured. 388: Improve handling of QualifiedValues/QualityCodes in expressions Added the following expression functions: isUncertain isBad isError isBadOrError qualityOf timestampOf In addition, overloaded the equality operation in exp…

The gist: In addition to `isGood`, we've added new expression functions to test each different level (`isBad`, `isUncertain`, `isError`).

As a further mechanism to allow direct comparison, e.g. if you want to find out if something is disabled, you can use the new `qualityOf` expression; this will return the QualityCode object from the input. The equality operator has been 'overloaded' for QualityCodes in expressions, so you can directly compare against the (modern) string constants or integer values:  
`qualityOf({tag}) = 515`  
or  
`qualityOf({tag}) = "Bad_Disabled"`

Note that any value outside of the 'reserved' 0-1024 range for IA codes will need to be the somewhat opaque 32-bit integer code. It's a mask on the most-significant 2 bits of a 32 bit value (representing the level; `Good(0b00), Uncertain(0b01), Bad(0b10), Error(0b11)`) and the 'user code', which can be any other integer value. This is unlikely to matter to anyone unless they're using a module that implements their own custom QualityCodes.

Scripting is not affected by these changes, so the `getCode()` mechanism above detailed higher in the thread is still the 'best' way to store modern codes into a database.
