Reading OPC Tag Quality Codes in Siemens WinCC Runtime

David Krause13 min read
HMI / SCADASiemensTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

1. Problem Overview

When a Siemens WinCC station acts as an OPC Data Access (DA) client, two different "status" concepts coexist in the runtime:

  • Link Quality — describes the health of the connection between the OPC server process and the WinCC client process. This is what WinCC Explorer > Tag Management > mouse-over tooltip reports, and it normally shows "Connection OK" even when the underlying field device is unreachable.
  • Tag Quality (OPC Quality Code) — carried per-tag as a 16-bit code defined by the OPC DA specification. It tells the consumer whether the value is Good, Bad, or Uncertain, with subcodes that report sensor failures, out-of-range, communication loss, etc.

Operators need the per-tag quality, not just the link state, especially on unstable media such as radio modems where the OPC server may keep the link alive but every tenth read attempt returns a stale or out-of-range value.

The classic WinCC V5.1 release pre-dates the public exposure of the runtime quality helpers that arrived in the V6.0 SP3 information system. If you must remain on V5.1, the supported technique is to evaluate the device-published integer status word and use the C-GetTag* API to surface it to operators — see Section 5. From V6.0 SP3 onward (PCS 7 V6.x, V7.x, WinCC Professional / Unified), the dedicated bit-state helper functions are documented and callable from any global or picture C action.

2. OPC DA Quality Code Model

Every OPC DA item carries a 16-bit quality word. The semantics are fixed by the OPC Data Access 3.0 specification, so a Siemens WinCC client reading a third-party server (e.g. Lectus Modbus OPC) still receives the same encoded severity / substatus / limit bits.

Bit(s) Field Values Meaning
7-6 Quality 0 = Bad
1 = Uncertain
2 = Good
3 = N/A
Top-level severity reported to the operator
5-0 Sub-status Enum within each quality group Specific condition (config error, sensor failure, comms loss, last usable value…)
4 Limit bit 0 = not limited
1 = limited
Combined with sub-status 2/3 to mark low/high
15-8 Vendor-specific — Server-defined extension; not portable

Common sub-status values you will encounter on a radio / serial media:

Quality Sub-status Name Operator interpretation
Bad 0x01 CONFIG_ERROR Tag definition does not map to a valid item on the server
Bad 0x02 NOT_CONNECTED OPC server has lost the link to the device
Bad 0x04 DEVICE_FAILURE Server can reach the device but the device returned an error
Bad 0x05 SENSOR_FAILURE Sensor signal lost (cable break, RTD burnout)
Bad 0x08 COMMUNICATION_FAILURE I/O driver / Modbus exception / timeout
Uncertain 0x40 SUBSTITUTE Server is publishing a manual override value
Uncertain 0x50 SENSOR_CAL Value is out of calibration range
Uncertain 0x60 LAST_USABLE Last good value, no recent update
Good 0x00 OK Value is fresh and valid
Good 0xC0 / 0x40 LOCAL_OVERRIDE / LIMIT_OK Value is forced or near a configured limit

The full table is replicated in Siemens TIA Portal V20 documentation under the OPC UA connection topic for WinCC Runtime Professional.

3. Why Tag Management Tooltips Are Not Enough

The WinCC Explorer shows two indication surfaces:

  1. Tag Management tooltip — paints a green/red icon based on whether the WinCC internal tag exists and is linked. This state is updated by the OPC client daemon inside WinCC; it does not look at the per-item quality coming back from the read.
  2. Internal OPC diagnostic channel — visible only on dedicated diagnostic pictures that subscribe to the server's own status groups.

For a customer-facing HMI picture you must surface a per-IO-field warning that mirrors the OPC sub-status. This is done by calling the WinCC C-API helpers described in Section 4 from a scheduler (1 s) or value-driven trigger.

4. WinCC Runtime API for Quality Codes

The C-script / VBS-script API exposes several quality-aware variants of the standard tag read functions. Each one returns the raw 16-bit OPC quality word in an output parameter, not a Boolean — this is critical because a project may want to differentiate the four severity buckets (Good / Uncertain-not-limited / Uncertain-limited / Bad).

Function Data type Header Notes
GetTagBitStateQC(Tagname, BYTE *Quality, BYTE *State) Bit / discrete apdefap.h Returns State = bit value, Quality = raw OPC code. Listed in WinCC Information System under "example_GetTagBitStateQC" from V6.0 SP3 onward.
GetTagByteStateQC(...) BYTE apdefap.h Same idea for 8-bit tags.
GetTagWordStateQC(...) WORD apdefap.h 16-bit internal tags.
GetTagDWordStateQC(...) DWORD apdefap.h 32-bit process values.
GetTagFloatStateQC(...) float apdefap.h Analog measurements.
GetTagDoubleStateQC(...) double apdefap.h Counters / double-precision tags.
GetTagRawStateQC(...) RAW apdefap.h OPC raw value with quality word.

All seven families share the same signature pattern: the variable parameters are received by pointer so the function can write multiple outputs, and they return TRUE on success and FALSE if the tag was not found in Tag Management.

5. C-Script Implementation Template

The following action is suitable for an ApDiagnostics-style picture. It evaluates three tags from a Lectus Modbus OPC channel and writes aggregated severity into internal flags that drive a status bar.

/* ------------------------------------------------------------------
 * project : apdiag.c
 * triggered : 1 s scheduler in WinCC Graphics
 * purpose  : Decode OPC DA quality codes and raise operator warnings
 * valid for: WinCC V6.0 SP3 .. V7.5 SP2
 * ------------------------------------------------------------------ */
#include "apdefap.h"

#define OPC_Q_MASK           0x00C0   /* bits 7-6 = severity */
#define OPC_Q_BAD            0x0000
#define OPC_Q_UNCERTAIN      0x0040
#define OPC_Q_GOOD           0x00C0

#define OPC_SS_COMMFAIL      0x08     /* sub-status 0x08 = comm fail    */
#define OPC_SS_NOTCONNECTED  0x02     /* sub-status 0x02 = not linked   */
#define OPC_SS_LASTUSABLE    0x60     /* sub-status 0x60 = stale value  */

BOOL UpdateQuality(const char* tag, BYTE* qOut)
{
    DWORD rawValue  = 0;
    BYTE  quality   = 0;
    BYTE  state     = 0;

    /* Choose the correct function variant for the tag's data type */
    BOOL ok = GetTagDWordStateQC(tag, &rawValue, &quality, &state);
    if (!ok) {
        *qOut = 0xFF;                /* 0xFF = WinCC client-side error  */
        return FALSE;
    }

    *qOut = quality;
    return TRUE;
}

void OnTimer(void)
{
    BYTE qTankLevel, qModbusLink, qRemoteValve;
    DWORD opFlags = 0;               /* bits packed into "opStatus" tag */

    UpdateQuality("OPC_TankLevel",   &qTankLevel);
    UpdateQuality("OPC_ModbusLink",  &qModbusLink);
    UpdateQuality("OPC_RemoteValve", &qRemoteValve);

    if ((qTankLevel   & OPC_Q_MASK) == OPC_Q_BAD        ||
        (qTankLevel   & 0x0F)        == OPC_SS_COMMFAIL ||
        (qModbusLink  & OPC_Q_MASK) == OPC_Q_BAD)
        opFlags |= 0x01;             /* bit 0 = "radio link lost"       */

    if ((qRemoteValve & 0x0F) == OPC_SS_NOTCONNECTED)
        opFlags |= 0x02;             /* bit 1 = "valve channel offline" */

    if ((qTankLevel   & OPC_Q_MASK) == OPC_Q_UNCERTAIN  &&
        (qTankLevel   & 0x0F)        == OPC_SS_LASTUSABLE)
        opFlags |= 0x04;             /* bit 2 = "stale level - last value" */

    SetTagDWord("opStatus", opFlags);
}

The internal tag opStatus is then evaluated on the picture by three coloured graphic objects that show different text strings based on (opStatus & 0x01), (opStatus & 0x02), (opStatus & 0x04).

For V5.1 deployments where GetTagDWordStateQC is not yet documented, fall back to the device-side status word (e.g. the integer percentage you already have from the radio modem) and apply your own thresholding in C-script. The principle is identical — derive an internal DWORD and drive the status bar from it — but the bit semantics are no longer OPC-compliant; document the meaning in the picture's properties.

6. VB-Script Equivalent

WinCC V7 onwards allows picture-level VBScript. The same logic in scripting language is shorter and easier for plant electricians to maintain:

'-------------------------------------------------------------
' Picture script - WM event when "opStatus" tag changes
'-------------------------------------------------------------
Dim qMask, qByte, sText

qByte = SmartTags("opQuality_TankLevel")
qMask = qByte And &H00C0

Select Case qMask
    Case &H00C0 : sText = "OK"
    Case &H0040
        Select Case (qByte And &H0F)
            Case &H60 : sText = "Stale (last good)"
            Case &H40 : sText = "Substitute value"
            Case Else : sText = "Uncertain"
        End Select
    Case &H0000
        Select Case (qByte And &H0F)
            Case &H02 : sText = "Channel offline"
            Case &H04 : sText = "Device failure"
            Case &H08 : sText = "Comms failure"
            Case Else : sText = "Bad (other)"
        End Select
    Case Else   : sText = "n/a"
End Select

SmartTags("txtQualityHint") = sText
ShowSymbol "picWarn", (qMask = &H0000)

Drive SmartTags("opQuality_TankLevel") from an internal tag that is filled by an internal OPC subscription using the quality check-box in the tag properties dialog of WinCC Tag Management.

7. Migration Path: V5.1 / V6.0 SP3 / V7.x / TIA Unified

The OPC client API surface changed considerably across releases. The table below is the supported implementation route per release.

WinCC Release How to expose OPC quality Caveat
V5.1 (deprecated) Use device status integer; no first-class quality helper Operator messaging must be derived manually; treat as best-effort
V6.0 SP3 / V6.2 (PCS 7 V6) GetTag*StateQC documented in information system; example example_GetTagBitStateQC Install PCS 7 add-on if the helpers are missing from the integrated information system
V7.0 / V7.2 / V7.4 / V7.5 GetTag*StateQC fully supported; VBScript equivalent via SmartTags(...) subscription Verify that Quality propagation is enabled in the OPC channel's "Tag Properties > Options > Quality"
TIA Portal WinCC Professional (V15-V19) Use the OPC UA / OPC XML DA channel and read the value with the Items collection; quality exposed as QualityID on the HMI tag Legacy DA-only servers need the "DA-UA wrapper" configuration object
TIA Portal WinCC Unified (V17-V20) Tag browser exposes the State and Quality columns for OPC UA sourced HMI tags Configure the OPC UA connection per the Creating OPC UA tags (RT Professional) and Creating OPC tags (RT Unified) procedures

8. Configuring OPC UA Tags in WinCC Unified

The TIA Portal V20 documentation for WinCC Runtime Unified walks the project-tree path below when you need the per-tag quality to travel from the OPC UA server into a faceplate:

  1. Open the project tree, expand "HMI tags", double-click the tag table.
  2. In the Name column, double-click "Add".
  3. Set the connection to the existing OPC UA connection (formerly created under "Connections" > OPC UA).
  4. Browse to the remote OPC UA node. The dialog shows the Quality column; tick "Use server-supplied quality".
  5. On the faceplate, bind the value display to the tag and bind a separate visibility property to (Quality == Good). The quality is available as tag.Quality in JavaScript / VB script.

For WinCC Professional (TIA) the procedure is documented at docs.tia.siemens.cloud. For WinCC Unified (TIA) the same firm's portal provides the matching reference at docs.tia.siemens.cloud.

9. Channel Status vs. Device Status Decision Matrix

Symptom in WinCC Explorer tooltip OPC quality expected Root cause Recommended operator message
Green "OK" Good (0xC0) Healthy link, healthy device None — normal operation
Green "OK" Bad - Comm Failure (0x08) OPC server can reach the device at the protocol layer but the device replies with exception / no response for the specific item (timeout, stale Modbus map) "Communication failure – check radio / cabling"
Red "broken" Bad - Not Connected (0x02) OPC server has not loaded the device driver or the server process is restarting "Channel offline – restart OPC server"
Green "OK" Uncertain - Last Usable (0x60) Server is publishing the cached value because the read retry budget is exhausted "Stale value – last good reading shown"
Red "broken" Uncertain - Substitute (0x40) Server is forcing a manual value (operator simulation mode) "Manual override active – value not live"
Green "OK" Bad - Sensor Failure (0x05) I/O module detected burnout / over-range "Sensor fault – check field device"

10. Troubleshooting Matrix

Error Most common cause Diagnostic step Fix
GetTagBitStateQC returns FALSE for every OPC tag Quality propagation unchecked in Tag Management Right-click the channel > Properties > Options > tick "Quality" Re-compile OS, restart runtime
Quality is always Good (0xC0) on a deleted client Client-side cache not invalidated Subscribe to ServerState change events and force refresh Re-add subscription; see vendor note on stale Good flags
Sub-status changes but operator message doesn't Script trigger too slow Check trigger: standard cycle vs. tag change trigger Use "On change" trigger with debounce 500 ms
C-script quality variable not declared Missing header reference Insert #include "apdefap.h" Rebuild picture
WinCC V6.0 SP2 does not list GetTagBitStateQC Older information system build Search the help system index for "example_GetTagBitStateQC" - confirm SP level Install Siemens PCS 7 V6.0 SP3 / V6.1 add-on
Quality code returns 0xFF WinCC client lost connection internally (different from device link) Check apdiag picture; verify OPC server is running as a service Re-create channel, restart OPC server service

Note: scenarios where a deleted OPC-UA client keeps reporting Good quality for a stale value are a known class of edge cases; see Inductive Automation knowledge base for a vendor-neutral description of this behaviour that also applies to OPC DA based wrappers and the rationale for always trusting sub-status rather than the top-level severity alone.

11. Commissioning Verification Checklist

  1. Open the diagnostic picture apdiag.pdl, set the picture-cycle update to 500 ms.
  2. Disconnect the field cable or power down the radio modem. Confirm the opStatus bit pattern changes within 1 s.
  3. Use the WinCC Online Trend Control to plot the qByte value; verify it walks through 0xC0 → 0x48 → 0x08 as the device degrades from "OK" to "Uncertain-not-limited" to "Bad-comm-failure".
  4. Restart the OPC server process while WinCC is running. Verify the link-quality tooltip updates within 10 s (server dependent) and the per-tag quality returns to Good once the cache invalidates.
  5. In WinCC Unified, simulate a broken UA subscription by remapping the node to a non-existent path and confirm that the faceplate's quality expression evaluates to Bad.
  6. For each release, archive the C / VBScript project in the customer archive so the quality-evaluation source can be re-deployed during a plant re-commissioning.

12. Frequently Asked Questions

What OPC DA quality codes can WinCC Runtime interpret?

WinCC Runtime handles the full 16-bit OPC DA quality word. The C functions GetTag*StateQC (e.g. GetTagBitStateQC, GetTagDWordStateQC, GetTagFloatStateQC) return the raw quality byte, allowing scripts to differentiate Good (0xC0), Uncertain sub-statuses 0x40 and 0x60, and Bad sub-statuses 0x02, 0x04, 0x05, 0x08 that are typical for sensor and radio link faults.

Why does the WinCC Tag Management tooltip show "Connection OK" while the value is clearly wrong?

The tooltip only reflects the health of the OPC client connection between WinCC and the OPC server process — not the path between the OPC server and the field device. You must read the per-tag OPC quality code with a C or VB script action and trigger the operator message from that script, otherwise the failure on the field side remains invisible to the operator.

Is GetTagBitStateQC available in WinCC V5.1?

No. The function family is documented only from WinCC V6.0 SP3 onward (index entry example_GetTagBitStateQC). On V5.1, derive a quality indicator from the device's own status integer (for example a radio-quality percentage) and use standard GetTagDWord / SetTagDWord APIs to drive an operator message.

How do I expose OPC UA quality in WinCC Unified?

In TIA Portal V20 for WinCC Unified, open HMI tags, create an HMI tag using the OPC UA connection, and tick Use server-supplied quality. The quality is then accessible from faceplates as the tag's Quality property and from JavaScript as tag.Quality, with severity per the OPC DA / OPC UA mapping.

What is the difference between WinCC link-quality and OPC DA tag quality?

Link quality is a boolean WinCC internal state managed by the OPC client (visible in the Tag Management tooltip). OPC DA tag quality is a 16-bit code per OPC item returned by the server, encoding severity, sub-status, and limit bits. Only the OPC DA quality can distinguish the four useful states Good, Uncertain-stale, Bad-comm-failure, and Bad-not-connected needed for accurate operator messaging.

Can an OPC-UA server keep reporting Good quality after the client is deleted?

Yes. This is a well-known edge case in OPC UA subscription cache handling where the cached value flag remains Good while the actual value is stale. Always couple the top-level severity with the sub-status byte (for example 0x48 for Uncertain-not-limited) before deciding on an operator message.

Which C header do I include for the quality helpers?

Include apdefap.h in every global or picture-level C action that calls GetTag*StateQC. The header ships with the standard WinCC installation; no separate add-on is required from V6.0 SP3 onward.

Back to blog