Quality Codes
The AspenTech Inmation getvalue and setvalue functions are commonly used to read and write VQT combined values to objects in the namespace. System objects use OPC UA quality codes as standard but there are circumstances where unusual quality code values might be displayed or returned when using the system APIs with OPC UA or OPC Classic server I/O items.
In these circumstances the returned quality code might be a 32 or 36 byte string that provides information to the system but is not recognizable as an OPC quality code to the user.
If the bit string is of OPC Classic or OPC UA origin, it can be interpreted as being "good", "bad" or uncertain by using the , isgoodstatus, isbadstatus and isuncertainstatus functions.
These strings can be further translated using the syslib.api-quality library to return a recognizable OPC quality code and the origin of the quality value.
The syslib.api-quality library is called using the require function to access the library functions.
Translate Unrecognized Quality Codes
The following example uses the syslib.api-quality library’s qualityCode method to return the lower 32 bits of the quality value of an OPC Classic item. The bit mask is interpreted to indicate whether the quality code is OPC UA or OPC Classic and human readable quality text can be provided.
local apiQuality = require('syslib.api-quality')
local path = "/IO-Home/Matrikon.OPC.Simulation.1/Simulation Items/Random/Int1"
local _, quality = syslib.getvalue(path)
local qualityCode = apiQuality:qualityCode(quality)
local res = {}
table.insert(res, {['quality'] = quality })
table.insert(res, {['qualityCode'] = qualityCode })
table.insert(res, {['qualityCodeHEX'] = string.format("0x%08X", qualityCode) })
table.insert(res, {['isOPCClassic'] = apiQuality:isOpc(quality) })
table.insert(res, {['qualityText'] = apiQuality:qualityText(quality) })
table.insert(res, {['qualityType'] = apiQuality:qualityType(quality) })
return res
The isOpc, qualityType and qualityText methods in this library help determine more details about the content of bit mask.
This script returns a table containing all the information encoded in the bit mask.
[
{
"quality": 4294901952
},
{
"qualityCode": 4294901952
},
{
"qualityCodeHEX": "0xFFFF00C0"
},
{
"isOPCClassic": true
},
{
"qualityText": "Good"
},
{
"qualityType": "Opc"
}
]
In this example the VQT was read from an OPC Classic item with "good" quality. The first 16 bits of the 32 bit quality bitmask are used, indicating that this is an OPC Classic quality code (isOPC method returns "true" ). The second 16 bits contains the OPC Classic status code information.
History Calls - Quality Codes
History calls on I/O items and AspenTech Inmation objects in the namespace will return different quality status codes depending on the type of item (OPC Classic, OPC UA), whether an aggregate was used and how the history value was stored (historical values can be set in Lua using syslib.setvalue and syslib.sethistory).
AspenTech Inmation regards all "good" qualities as "0" regardless of the OPC type. History calls that retrieve VQT with good quality status will return "0" and not necessarily a OPC-type specific quality code (for example OPC DA I/O items "good" quality historized values are returned as "0" not "192").
Raw Q values other than "good" will be stored using the quality code specific to the OPC standard of the item. For example, "bad" and "uncertain" Q values from OPC DA codes are stored using the codes specified in the OPC Classic standard. AspenTech Inmation objects use OPC UA quality codes by default, however, if quality codes (OPC Classic or otherwise) are set using the Lua or Web API, those defined Q codes will be stored in the repository as part of the VQT.
It is important to note that if the Lua API or Web API are used to set Q values (rather than Server defined Q codes) these Q codes will be stored in the repository. Q codes that are not recognized as belonging to any standard will still be archived.
Setting history values with Lua API
The AspenTech Inmation Lua API allows history values to be set for items using 2 functions: syslib.setvalue and syslib.sethistory).
The difference in how these two functions work can lead to a difference in the quality codes returned when doing history calls.
The syslib.setvalue function allows you to set historical values for an item by providing past timestamps as optional arguments. You can also set the quality in the optional arguments. If setting a value to an OPC Classic or OPC UA I/O item, the value is sent via the OPC server to the item and historized via OPC Server-ingress Node-archive Node communication to the MongoDB repository. In these cases, using syslib.setvalue to set an OPC Classic quality code to an OPC UA I/O item (or vice-versa) will result in the code being converted to a Q code in the appropriate OPC standard (the conversion will be to a generic "good", "bad" or "uncertain" code).
| If using syslib.setvalue this way with OPC I/O items, be aware that the OPC server will need more time to acknowledge and process each setvalue request. The syslib.sethistory) function is different from setvalue in that the OPC server is not involved and VQT data will be written directly to the repository. This means that there is no conversion of Q codes and the Q code written in the script, will be written to the repository. Any history calls on the items will therefore return the same Q code that was used as an argument in the syslib.sethistory) function. |
| It is not recommended to mix and match OPC specified codes across OPC Classic/UA servers when using the sethistory function as this can lead to confusion, compliance and processing problems later down the line. |
Aggregates
History calls requesting aggregates (using the syslib.gethistory function) for items history stored in the AspenTech Inmation repository, will return values with varying quality codes dependent on the chosen aggregate. In general, all requested aggregates (apart from raw history calls) will return quality codes with OPC UA like quality codes as detailed in the OPC UA standard Depending on the chosen aggregate, the bitmask for the quality code will be amended with a 4 bit aggregation code, increasing the bitmask size to 36 bits. The possible values of this aggregation code are detailed in the documentation for the syslib.gethistory function.
Using the syslib.api-quality library methods again, the 32 bit quality code bitmask can be extracted from the 36 bit extended bitmask.
local apiQuality = require('syslib.api-quality')
local path = "/IO-Home/Matrikon.OPC.Simulation.1/Simulation Items/Random/Int1"
local now = syslib.currenttime()
local old = now - 60 * 1000
local intervals = 3
local rs = syslib.gethistory({path}, old - 1, now + 1, intervals, {"AGG_TYPE_INTERPOLATIVE"}, 100, 100, false, false)
local qualities = {}
table.insert(qualities, rs)
for i=1, #rs[1] do
local quality = rs[1][i].Q
local qualityCode = apiQuality:qualityCode(quality) -- Returns the lower 32 bits of a qword. Typically this is the UA status code or Classic OPC quality with its mask.
local res = {}
table.insert(res, {['quality'] = quality })
table.insert(res, {['qualityCode'] = qualityCode })
table.insert(res, {['qualityCodeHEX'] = string.format("0x%08X", qualityCode) })
table.insert(res, {['isOPCClassic'] = apiQuality:isOpc(quality) })
table.insert(res, {['qualityText'] = apiQuality:qualityText(quality) })
table.insert(res, {['qualityType'] = apiQuality:qualityType(quality) })
table.insert(qualities, res)
end
local json = require'dkjson'
return json.encode(qualities)
This script returns the history call in a json with the interpolative aggregated VQTs. The last 32 bits of the 36 bit quality code are extracted to show the OPC UA quality code.
[
[
[
{
"T": 1576247745199,
"Q": 17179869184,
"V": 76
},
{
"T": 1576247765200,
"Q": 17179869184,
"V": 121
},
{
"T": 1576247785201,
"Q": 17179869184,
"V": 59
}
]
],
[
{
"quality": 17179869184
},
{
"qualityCode": 0
},
{
"qualityCodeHEX": "0x00000000"
},
{
"isOPCClassic": false
},
{
"qualityText": "Good"
},
{
"qualityType": "OpcUa"
}
],
[
{
"quality": 17179869184
},
{
"qualityCode": 0
},
{
"qualityCodeHEX": "0x00000000"
},
{
"isOPCClassic": false
},
{
"qualityText": "Good"
},
{
"qualityType": "OpcUa"
}
],
[
{
"quality": 17179869184
},
{
"qualityCode": 0
},
{
"qualityCodeHEX": "0x00000000"
},
{
"isOPCClassic": false
},
{
"qualityText": "Good"
},
{
"qualityType": "OpcUa"
}
]
]
Expected Quality Codes
The following table gives an overview of what quality codes should be expected to be returned when using the Lua API to read real time and history values from different objects in the namespace. The OPC Classic and OPC UA specifications should be consulted for further explanation of VQT quality codes.
| Lua Function | AspenTech Inmation Object (Data Holder/Action Item etc.) | I/O item OPC Classic | I/O item OPC UA |
|---|---|---|---|
syslib.getvalue |
Good = 0 Bad = OPC UA Quality code |
Good = 0 Bad = OPC Classic Quality code |
Good = 0 Bad = OPC UA Quality code |
syslib.getrawhistory |
Good = 0 Bad = OPC UA Quality code |
Good = 0 Bad = OPC Classic Quality code |
Good = 0 Bad = OPC UA Quality code |
syslib.gethistory - Aggregates |
Good = 0 Bad = OPC UA Quality + Aggregate Status Code Uncertain = OPC UA Quality code + Aggregate Status Code |
Good = 0 Bad = OPC UA Quality + Aggregate Status Code Uncertain = OPC UA Quality code + Aggregate Status Code |
Good = 0 Bad = OPC UA Quality + Aggregate Status Code Uncertain = OPC UA Quality code + Aggregate Status Code |