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, orUncertain, 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.
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:
- 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.
- 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).
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:
- Open the project tree, expand "HMI tags", double-click the tag table.
- In the Name column, double-click "Add".
- Set the connection to the existing OPC UA connection (formerly created under "Connections" > OPC UA).
- Browse to the remote OPC UA node. The dialog shows the Quality column; tick "Use server-supplied quality".
- On the faceplate, bind the value display to the tag and bind a separate visibility property to
(Quality == Good). The quality is available astag.Qualityin 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
- Open the diagnostic picture apdiag.pdl, set the picture-cycle update to 500 ms.
- Disconnect the field cable or power down the radio modem. Confirm the
opStatusbit pattern changes within 1 s. - Use the WinCC Online Trend Control to plot the
qBytevalue; verify it walks through0xC0 → 0x48 → 0x08as the device degrades from "OK" to "Uncertain-not-limited" to "Bad-comm-failure". - 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
Goodonce the cache invalidates. - 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. - 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.