WinCC Flexible Text List Alarm History: Script-Based Log Method

David Krause14 min read
SiemensTroubleshootingWinCC
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

Problem Statement

WinCC Flexible 2008 / WinCC Flexible 2008 SP3 (and earlier TIA Portal WinCC Comfort/Advanced predecessors) display alarm text via two distinct mechanisms: Alarm lists (driven by bit/discrete triggers or limit-value monitoring) and Text lists (driven by tag value change). When a project uses a Text list tied to a single WORD tag (for example a DBW on an S7-300/400 PLC), the visible alarm text reflects the current value of that tag. As soon as the tag value changes, the prior notification text is overwritten and disappears from the HMI screen. The engineer cannot migrate to a standard alarm list because the trigger source is itself a numeric WORD coming from the PLC, and WinCC Flexible's built-in alarm logging cannot be conditioned on "equals specific value" without a script.

The net symptom: only the last text-list message is ever visible. The previous nine — required by the operator's spec — are lost. This article documents the script-based workaround using the AlarmLog object and a cyclic VBScript routine that reads the current text list index, resolves it to a string, and pushes the entry into a user archive that can be displayed on a custom alarm view.

Root Cause: Text List vs. Alarm List Trigger Semantics

Understanding the limitation requires looking at the underlying trigger model in WinCC Flexible's runtime:

Property Text List Alarm List (Bit / Limit)
Trigger source Any tag (INT/WORD) — fires on value change Discrete bit or analog limit (high/low) on a tag
Event retention None — display reflects current value only Built-in logging in AlarmLog with acknowledge / clear states
Number of simultaneously visible entries 1 (current value) Configurable queue (depends on configured buffer size)
PLC tag requirement Numeric tag (BYTE/WORD/DWORD/INT) Bit tag for discrete, or any tag with configured limits
Time stamp Not stored automatically Automatic (PLC or HMI time, configurable)

WinCC Flexible's OnValueChanged event for a tag is the only built-in mechanism that fires when a WORD transitions to a new value. The text list is bound to that event, so it is a stateless renderer — it always shows what the tag currently equals. There is no concept of a "history" within a text list itself.

The built-in alarm system, by contrast, generates a discrete AlarmEvent object every time a configured bit goes high or an analog goes out of limit. Each event is timestamped, queued, and can be acknowledged. But you cannot configure a discrete trigger that says "fire an alarm when tag X equals 5." You can only say "fire when tag X exceeds limit L." Hence the engineering deadlock: the PLC provides a code number, not a bit pattern, and the HMI must decode it into a human-readable string.

Engineering note: If you control the PLC code, the cleanest fix is to expose 10 discrete bits from the PLC (one per active alarm state) and let the HMI's standard alarm system handle the queue. The text-list workaround is only necessary when the PLC cannot be modified, when the alarm source already arrives as a numeric code, or when a long retrofit is in progress.

Solution Architecture: Text List → Script → User Archive → Custom View

The script-based method reproduces alarm-list behavior on top of a text list. The data path is:

  1. PLC tag (DBW) writes a numeric code into the HMI tag.
  2. Text list is bound to that HMI tag and resolves the code to a string at display time.
  3. VBScript scheduled task runs on a 500–1000 ms cycle. It reads the current text-list index, compares it to the previously stored index, and when a change is detected, writes a new record into a User Archive (CSV-backed) or into an internal tag array.
  4. Custom alarm view on the HMI screen is configured as an Alarm Control with a filter that displays only the user-archive records, ordered newest-first, with scrollable history.

Components required on the HMI project side:

  • One HMI tag of type WORD or INT mirroring the PLC DBW.
  • One Text list with N entries mapping each code (0..N-1) to its display string.
  • One internal tag of type WORD named LastIndex to remember the previously displayed value.
  • One User Archive (CSV file) named AlarmArchive with columns: TimeStamp (STRING 20), Code (WORD), Message (STRING 50), State (STRING 10).
  • One scheduled VBScript task running every 500 ms.
  • One screen with an Alarm Control object bound to the User Archive via ODBC or direct CSV reference.

Step-by-Step Implementation

1. Create the text list

In the WinCC Flexible project tree, right-click Text and Graphic Lists → Text Lists and create a list named AlarmTexts. Add one entry per alarm code, for example:

Value Text (English) Text (German)
0 No active alarm Kein Alarm
1 Motor overload trip Motorüberlast
2 Coolant pressure low Kühlmitteldruck niedrig
3 Spindle temperature high Spindeltemperatur hoch
4 Door interlock open Türverriegelung offen
5 Hydraulic filter dirty Hydraulikfilter verschmutzt
10 E-Stop pressed Not-Halt gedrückt
20 Servo drive fault Servo-Antriebsfehler
99 Unknown code Unbekannter Code

Bind the text list to a screen IO field or Symbolic IO field with output mode Text list and selection AlarmTexts. Confirm in RT that the displayed string updates when the HMI tag value changes.

2. Create the user archive

Open Archives → User Archives and create AlarmArchive with the columns above. The archive is a CSV file stored on the HMI panel's flash or under \Storage Card\Logs\ on PC-based runtime. Configure the archive to be a limited ring buffer; 1000 records is a reasonable default for a single shift and consumes roughly 80 KB.

Column Data type Length Notes
TimeStamp STRING 20 Format YYYY-MM-DD HH:MM:SS
Code WORD — Numeric code as received from PLC
Message STRING 50 Resolved text from text list
State STRING 10 "ACTIVE" / "CLEARED"

3. Configure internal tags

  • AlarmTag — type WORD, sourced from PLC DBW (e.g. DB100.DBW0). Connected to the text list.
  • LastIndex — type WORD, internal, persisted to retain value across screen changes. Used by the script to detect transitions.
  • LastState — type STRING, internal, 10 chars. Used to remember if the previous record was ACTIVE or CLEARED so that returning to code 0 emits a CLEARED event.

4. Write the scheduled VBScript

Open Schedules → Tasks and create a task with trigger Cyclic, 500 ms. Paste the following into the VBScript editor:

'------------------------------------------------------------------
' Archive text-list alarm transitions into a User Archive.
' Runs every 500 ms in WinCC Flexible RT.
'------------------------------------------------------------------
Option Explicit

Dim curCode, prevCode, curText, curState, prevState
Dim archiveName, oArchive, oRecordset
Dim timeStr

archiveName = "AlarmArchive"

curCode  = SmartTags("AlarmTag").Value
prevCode = SmartTags("LastIndex").Value
prevState = SmartTags("LastState").Value

' Resolve text list entry by index
curText = ""
Select Case curCode
    Case 0  : curText = "No active alarm"
    Case 1  : curText = "Motor overload trip"
    Case 2  : curText = "Coolant pressure low"
    Case 3  : curText = "Spindle temperature high"
    Case 4  : curText = "Door interlock open"
    Case 5  : curText = "Hydraulic filter dirty"
    Case 10 : curText = "E-Stop pressed"
    Case 20 : curText = "Servo drive fault"
    Case Else : curText = "Unknown code " & CStr(curCode)
End Select

' Determine state
If curCode = 0 Then
    curState = "CLEARED"
Else
    curState = "ACTIVE"
End If

' Only act on transition
If curCode <> prevCode Or curState <> prevState Then
    timeStr = Year(Now) & "-" & _
              Right("0" & Month(Now), 2) & "-" & _
              Right("0" & Day(Now), 2) & " " & _
              Right("0" & Hour(Now), 2) & ":" & _
              Right("0" & Minute(Now), 2) & ":" & _
              Right("0" & Second(Now), 2)

    Set oArchive = HMIRuntime.BaseScreenName.Parent.Parent.GetObject(archiveName)
    If IsNull(oArchive) Then
        HMIRuntime.Trace "Archive not found: " & archiveName & vbCrLf
        Exit Sub
    End If

    ' Append a record at the head of the user archive
    oArchive.MoveFirst
    oArchive.Add
    oArchive.SetFieldValue "TimeStamp", timeStr
    oArchive.SetFieldValue "Code",      curCode
    oArchive.SetFieldValue "Message",   curText
    oArchive.SetFieldValue "State",     curState
    oArchive.Update

    SmartTags("LastIndex") = curCode
    SmartTags("LastState") = curState
End If
Runtime note: HMIRuntime.BaseScreenName access varies slightly between WinCC Flexible 2008 and the TIA WinCC Runtime Advanced. For TIA-based projects, replace the GetObject call with HMIRuntime.Tags(archiveName).Read via an OLE DB wrapper, or use the documented UserArchiveControl scripting interface. Refer to the Siemens WinCC Flexible Programming and Reference Manual for the exact COM entry point supported by your RT version.

5. Display the archive in an Alarm Control

On the alarm screen, drop an Alarm Control object. Configure its source as User Archive → AlarmArchive. Enable the columns TimeStamp, Code, Message, State. Set sort order to TimeStamp descending. Set visible row count to 10 to match the operator's "show last 10 alarms" requirement. Tick Auto-scroll off so the operator can scroll the history without losing their place.

6. Optional: clear-on-acknowledge workflow

For an operator-acknowledge workflow, add a button on the alarm screen with the OnClick event:

Sub AcknowledgeSelected()
    Dim oView, oRow, oCol
    Set oView = ScreenItems("AlarmControl1").GetRowCollection()
    For Each oRow In oView
        oRow.SetFieldValue "State", "ACK"
    Next
End Sub

The state column becomes ACK and a visual flag can be added in the Alarm Control's column formatting.

Alternative: Internal Tag Array (No User Archive)

For panel-based runtimes (KP / KTP / TP panels with limited flash write endurance), avoid the CSV archive and store the last 10 entries in an array of internal tags. The trade-off is no persistent log across power-cycle:

' Shift registers of length 10
Dim i, tagName
For i = 9 To 1 Step -1
    tagName = "Hist_" & CStr(i)
    SmartTags(tagName).Value = SmartTags("Hist_" & CStr(i-1)).Value
Next
SmartTags("Hist_0").Value = curCode & "|" & curText

Create 10 string tags named Hist_0 through Hist_9 and display them in 10 symbolic IO fields on the screen, ordered with Hist_0 at top.

Verification and Acceptance Test

After the project is compiled and downloaded, perform this validation sequence on the live HMI before sign-off:

  1. Force AlarmTag = 1 from the PLC or via the HMI's tag simulation table. Confirm the text list shows Motor overload trip and a new row appears in the Alarm Control with code 1, state ACTIVE, current timestamp.
  2. Change AlarmTag to 3. Confirm row 2 appears with code 3 and row 1 (code 1) is still present above it in descending timestamp order.
  3. Continue cycling through codes 0, 5, 10, 20, 0. Confirm 7 rows are present and the most recent CLEARED event (code 0) is at the top.
  4. Return to AlarmTag = 1. Confirm an ACTIVE row is added again, not a duplicate of the original.
  5. Power-cycle the panel. On panels with persistent user archives, confirm all rows are still present after reboot. On panels with the array-only variant, confirm rows 1–10 are reset to empty strings.
  6. Disconnect the PLC connection while the script is running. Confirm the script does not write garbage to the archive; trace log should show the script exiting cleanly via Exit Sub in the catch block.
  7. Inject a code value not in the text list (e.g. 77). Confirm the row Unknown code 77 is added so unknown PLC states are still observable.

Performance, Footprint and Lifecycle Considerations

  • CPU load: A 500 ms cycle on a TP 177B / OP 177B consumes roughly 1–2 % CPU on the script alone. The User Archive CSV write is the dominant cost; if the panel is resource-constrained, raise the cycle to 1000 ms or switch to the internal-tag array method.
  • Flash wear: CSV user archives write a full file rewrite on each append on most panels. Limit the archive to 1000 records and accept that the file will eventually be cycled. For long-life applications (24/7, multi-year), export the CSV to a USB stick daily via a scheduled task instead of relying on the on-board flash.
  • Time stamp source: WinCC Flexible can use either the panel's local clock or the PLC's clock. For a multi-HMI cell, set all panels to use the PLC clock via Time Synchronization in the project settings; otherwise event ordering between panels is meaningless.
  • Language switching: The hard-coded Select Case strings above are language-specific. For multilingual deployments, read the current language ID from HMIRuntime.Language and select the matching text-list column. Alternatively, bind the script's curText to SmartTags("AlarmTag") and use the built-in text-list multilanguage feature by reading the appropriate index from the user-archive column.

When NOT to Use This Workaround

This script-based archive is appropriate when the PLC code is fixed and a discrete-bit alarm interface is impossible. It is not appropriate when:

  • The PLC can be modified to expose a bit per alarm state. Always prefer this option for new projects.
  • You are migrating to TIA Portal with WinCC Unified. Use the native Multiplexing tag feature and PLC alarm text lists introduced in WinCC V17 / TIA V17 — they solve this exact problem without scripts. Reference the SIMATIC WinCC Unified Engineering V18 Manual for the multiplex configuration path.
  • The HMI runtime is WinCC (PC-based, not Flexible). PC-based WinCC has direct WinCC AlarmControl + TagMultiplex and does not require this workaround.
  • SIL / safety-relevant alarms are involved. Use a Safety-Integrated alarm path; do not retrofit SIL events through a text list.

Troubleshooting Matrix

Symptom Likely Cause Action
Script fires but no row appears in Alarm Control User Archive is not bound to the control, or alarm view column names do not match the archive field names exactly Open Alarm Control configuration → Columns and confirm TimeStamp, Code, Message, State are present and bound to the archive fields
Every poll writes a new row even when code is unchanged LastIndex tag is not persisted, or HMI tag update is jittering on the LSB Mark LastIndex as Persistent. Add a hysteresis filter: only act when |curCode - prevCode| > 0 and the value has been stable for two consecutive cycles
Archive is empty after power-cycle User Archive persistence is not enabled in the project settings Open Archives → User Archives → AlarmArchive → Properties and enable Save archive retentively
Time stamp is wrong or 1970-01-01 Panel clock is not set, or the project was downloaded with the wrong time zone Set panel time via Control Panel → Date/Time on the device, or set up Time Master in the project with the PLC as the source
Script halts RT after a few hours Memory leak from opening the archive object without releasing it, or the file handle is exhausted Refactor to use Set oArchive = Nothing after each Update. Consider switching to the internal-tag array method
Code 99 displayed but PLC sends valid code 5 PLC and HMI use different byte orders (big-endian vs little-endian) on the WORD tag Set tag adaptation to Byte swap in the HMI tag properties, or change the PLC to use WORD in the correct byte order
Operator screen shows nothing for 30 s after a tag change Cycle is too long or the script is blocked by a long-running call Reduce the cycle to 250 ms, profile the script, and split I/O-bound work into smaller chunks

Migration Path: TIA Portal WinCC Unified

If a project is being modernized, the script-based workaround can be retired. In TIA Portal V17 and later, configure a Multiplexed tag on a WinCC Unified Comfort Panel. The multiplex tag accepts a WORD value and indexes into a text list, just like the old text list, but each transition also generates a discrete alarm event in the unified alarm system with a timestamp, state, and acknowledgement — exactly the behavior the operator originally requested. The configuration is under HMI Tags → [tag] → Properties → Multiplexing. Reference the SIMATIC WinCC Unified System Manual for the procedure.

Why does the text list show only one message at a time in WinCC Flexible?

WinCC Flexible text lists are stateless renderers. The text list is bound to a tag's OnValueChanged event, so the HMI always displays the string that corresponds to the tag's current numeric value. There is no built-in buffer for previous values — the previous string is overwritten the instant the tag changes.

Can a standard alarm list be triggered by a numeric code in a DBW?

No. The WinCC Flexible alarm system fires only on bit transitions (on/off) or on analog high/low limit violations. There is no built-in trigger that says "fire an alarm when tag X equals 5." To use a standard alarm list, expose 10 discrete bits from the PLC, one per alarm state, and bind each bit to a discrete alarm event.

What is the smallest VBScript routine to archive a text-list transition?

A 500 ms scheduled task that reads SmartTags("AlarmTag"), compares it to a persisted LastIndex tag, and on a transition writes a new row into a User Archive via oArchive.Add + oArchive.SetFieldValue + oArchive.Update. The full code is provided in Section 4 above.

Does the user archive persist across power-cycle on a TP panel?

Only if the archive property Save archive retentively is enabled in the project. Otherwise the CSV is regenerated empty on each boot. The internal-tag array alternative does not persist at all and is reset to empty on reboot.

Is there a native WinCC Unified replacement for this script?

Yes. In TIA Portal V17 or later, configure a Multiplexed tag on a WinCC Unified Comfort Panel. The multiplex tag indexes a WORD into a text list and emits a discrete alarm event on every transition, with timestamp and acknowledgement built in. No script is required.

Back to blog