Resolving WinCC VB Script Text List Import for CSV Logging

David Krause10 min read
SiemensTutorial / How-toWinCC
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

Overview

CSV-based process data logging on a Siemens Comfort Panel or WinCC Runtime is straightforward: a VBScript opens a FileSystemObject, iterates through LinePrint calls, and closes the stream. The pattern that breaks at scale is hard-coded text. When the engineer embeds the literal string PF30, Pressure timeout directly in the script and then later edits the text list in TIA Portal, the CSV continues to emit the old wording. The same problem compounds across 40-50 error codes, 5 different machines, and 220-250 unique text strings.

This reference covers four engineered solutions that keep the HMI text list as the single source of truth while still allowing VBScript to write localized alarm messages to a USB-mounted CSV file:

  1. The built-in LookupText VBScript function for direct list-to-script resolution.
  2. Dynamic text lists driven by an integer PLC tag, with the displayed text piped back to the script via a paired string tag.
  3. PLC-resident string arrays (DB) referenced through SmartTags.
  4. The TIA Portal Openness API for batched export, import, and library synchronization of text and alarm lists across multiple HMI devices.

Problem: Hard-Coded Alarm Text in CSV Logging

A typical naive logging block looks like the snippet below. The script receives a numeric error code (1-100) from the PLC and writes the matching human-readable text into the CSV column labeled Alarm text.

If SmartTags("PFnumber") = 30 Then
  fo.LinePrint "PF30, Pressure timeout"
End If
If SmartTags("PFnumber") = 31 Then
  fo.LinePrint "PF31, Flow rate low"
End If

The problems with this approach surface quickly in production:

Symptom Root Cause Impact
Text drift between HMI and CSV Text list edited in TIA Portal; script copy left untouched Audit trail shows wrong failure description
220-250 string literals to maintain 40-50 codes x 5 machines Single-rename requires multi-file search/replace
Translated languages hard to support Literal string is monolingual Cannot leverage WinCC language switching
Per-machine variants explode combinatorially Each machine ID has its own code-to-text map Script balloon size and review cost

Solution Path Comparison

Criterion LookupText Dynamic Text List + PLC String PLC DB String Array Openness API
Single source of truth Yes (text list) Yes (text list) No (PLC DB) Yes (mastercopy library)
Live runtime update Yes Yes Yes Engineering-time only
Multi-machine support Per HMI text list Per HMI text list Per PLC DB instance Across HMI project tree
Translation handling Inherits WinCC language Inherits WinCC language Manual per language Inherits WinCC language
Engineering effort Low Medium Low (PLC side) High (tooling)
Best for 1 HMI, fixed code set 1 HMI, codes change often PLC already holds strings Fleet rollout, version sync

Solution 1: LookupText Function in VBScript

The LookupText function is the lowest-friction path. It is invoked from VBScript on the HMI runtime and resolves an index (or bit-pattern for bit-triggered lists) against the configured text list, returning the active language's display string.

Call shape (VBScript on WinCC Runtime):

Dim sAlarmText
sAlarmText = SmartTags("PFnumber").LookupText(SmartTags("PFnumber").Value)
fo.LinePrint sAlarmText

Worked example for the documented scenario where the PLC writes 30 into tag PFnumber on pressure-timeout:

  1. In the HMI text list PFError, define entry 30 = PF30, Pressure timeout.
  2. Add a second HMI text list PFError_CellB if the column must show only the description, or use a single list and post-process in the script.
  3. From the logging VBScript, call LookupText against the runtime tag value.
  4. Append the returned string to the CSV row with fo.LinePrint.
Runtime caveat: if the value passed to LookupText is outside the configured range, the function returns an empty string rather than an error. Add a guard: If Len(sAlarmText) = 0 Then sAlarmText = "Unknown code " & SmartTags("PFnumber").Value

Solution 2: Dynamic Text List with Paired PLC String

Dynamic text lists are a TIA Portal HMI feature where a single text list is bound to a runtime tag whose value selects which entry to display. They are the recommended pattern when the code set changes frequently or when the same alarm must drive both the on-screen field and the CSV column.

Architecture:

  • PLC integer tag ErrorNumber: the 1-100 code emitted by the program.
  • PLC string tag ErrorName: written by the PLC or mirrored from the text list via the HMI tag's value/display separation. WinCC exposes the selected text list entry as a string output that can be bound to a tag.
  • HMI text list PFError configured as dynamic, range 1-100.

VBScript consumption:

Dim sLine
sLine = SmartTags("ErrorNumber").Value & "," & SmartTags("ErrorName").Value
fo.LinePrint sLine

Because the HMI refreshes ErrorName automatically when ErrorNumber changes, the script does not need to know the text at all. Editing the text list entry 30 from PF30, Pressure timeout to PF30, Pressure rise too slow is sufficient; the next log line will carry the new wording.

Solution 3: PLC String DB as Text Source

For plants where the PLC is the authoritative engineering artifact (for example, when the same project is replicated across 20 controllers and HMIs), storing the error name strings inside a PLC data block removes any HMI-side reconfiguration.

PLC side (TIA Portal S7-1200/S7-1500, block DB_AlarmText):

TYPE "UDT_AlarmText"
  STRUCT
    Code   : INT;     // 1..100
    Name   : STRING[80];
  END_STRUCT;
END_TYPE

DATA_BLOCK "DB_AlarmText"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
  STRUCT
    Entries : ARRAY[1..100] OF "UDT_AlarmText";
  END_STRUCT
END_DATA_BLOCK

The HMI's WinCC VBScript reads the array by index:

Dim iCode, sText
iCode = SmartTags("PFnumber").Value
sText = SmartTags("DB_AlarmText").Entries(iCode).Name
fo.LinePrint sText
STRING length: the bracket length in STRING[80] declares the maximum characters including the two-byte length header in classic DBs. For optimized blocks (S7-1500), the string is stored in the standard Siemens WSTRING / STRING format. Keep the bracket large enough to hold the longest translated wording plus two bytes for the length field.

Solution 4: TIA Portal Openness API for Text List and Alarm List Management

When the goal is fleet-wide text list synchronization (multiple HMI devices, multiple projects, multiple TIA Portal versions), manual editing is not sustainable. The TIA Portal Openness API: Managing alarm text list in PLC and mastercopy library documentation describes the automation entry points that turn text list administration into a build-time script.

Openness API surface (cataloged in the linked manual):

  • Importing VB scripts from a folder - allows the logging script itself to be versioned and rolled out alongside the project.
  • Exporting text lists from an HMI device - dumps the configured PFError list to XML/CSV for diff/review.
  • Importing a text list into an HMI - restores the same list into a sibling HMI device or a rebuilt project.
  • PLC text lists to a library - promotes a mastercopy library so the text list becomes a global type reused by every project.
  • Managing alarm text list in PLC and mastercopy library - centralized edit of the alarm text for PLC-derived alarms that surface on the HMI.

Typical build-time C# pattern (illustrative - adapt to the exact Openness DLL version referenced in your TIA Portal installation):

// using Siemens.Engineering;
// using Siemens.Engineering.Hmi;
var project = TiaPortal.Processes[0].Projects.Open(new FileInfo(@"C:\Projects\LineA\LineA.ap21"));
foreach (HmiTarget hmi in project.HmiTargets)
{
    var textList = hmi.TextLists.Find("PFError");
    textList.Import(new FileInfo(@"C:\Texts\PFError_en.xml"),
                    HmiTextListImportMode.Overwrite);
}
project.Save();
Versioning: the Openness API ships as part of TIA Portal and the contract changes between major versions (V16, V17, V18, V19, V20, V21). Pin the API major version in your build script; the linked manual is the V21 reference.

Multi-Machine Text List Strategy

For a fleet of five machines whose error codes overlap but whose text differs, a pragmatic combination is:

  1. Define one text list per machine in the master project: PFError_M1, PFError_M2, ... PFError_M5.
  2. Promote those lists to a TIA Portal mastercopy library using the Openness API workflow described above.
  3. In the HMI tag table, expose a MachineID integer and a set of HMI tags that the runtime selects based on a multiplexed list reference.
  4. In the logging VBScript, route the lookup through the active list:
Dim sListName, sText
Select Case SmartTags("MachineID").Value
  Case 1 : sListName = "PFError_M1"
  Case 2 : sListName = "PFError_M2"
  Case 3 : sListName = "PFError_M3"
  Case 4 : sListName = "PFError_M4"
  Case 5 : sListName = "PFError_M5"
End Select
sText = SmartTags("PFnumber").LookupText(SmartTags("PFnumber").Value, sListName)
fo.LinePrint sText

This keeps the text list edit confined to one place per machine, eliminates the 220-250 hard-coded lines, and makes translation rollouts a text-list export/import rather than a script rewrite.

Edge Cases and Field-Proven Caveats

  • USB stick removal during write: wrap the fo.LinePrint calls in a On Error Resume Next / error code check, and buffer to a RAM disk first if the HMI supports it.
  • List scope mismatch: the value passed to LookupText must come from a tag of the same scope (HMI tag pointing to the same PLC address). Cross-scope calls return an empty string and silently break the CSV.
  • Language switching at runtime: LookupText honors the active WinCC runtime language. If the plant operates in DE/EN/FR, the CSV will switch with it. Confirm with the QA team whether a fixed-language column is required; if yes, force the language via the HMI tag's language attribute.
  • Bit-triggered lists: for alarm bit lists, LookupText returns a comma-joined string of all matching entries. Split the result with Split if only the first match is required.
  • Openness API licensing: the Openness API is shipped with TIA Portal; however, scripted modifications of a running project require that no other TIA Portal instance has the project open.
  • STRING size on Comfort Panels: older Comfort Panel firmware (V14.x and earlier) truncates STRING tags at 254 characters. Verify the panel firmware version before committing to a multi-language 400-character string.

Verification Procedure

  1. Force the PLC to write the code 30 into PFnumber using a watch table or a forced value.
  2. Trigger the logging event on the HMI (button, scheduled task, or value-change event).
  3. Remove the USB stick and open the CSV. Confirm the row shows the current text list entry for code 30, not the historical literal.
  4. Edit text list entry 30 in TIA Portal, recompile, download to the HMI, and repeat the trigger. The next CSV row must reflect the new wording without any VBScript change.
  5. Switch the runtime language to a second language and confirm the CSV output tracks the language switch.
  6. For Openness-based rollouts, run the import script against a sandbox project, then diff the resulting text list against the master XML to verify no entries were dropped.

Troubleshooting Matrix

Symptom Likely Cause Resolution
CSV column empty LookupText index out of range Confirm code falls within text list range; add guard for empty string
CSV shows stale wording VBScript literal not replaced by LookupText Search VBScript for residual hard-coded strings; refactor to call LookupText
Different wording per machine Single shared text list, not per-machine Create PFError_M1..M5; multiplex on MachineID in script
Openness import errors on TIA V20 project API version mismatch Pin Openness DLL to project TIA version; see linked V21 manual for version-specific syntax
String truncation in CSV PLC STRING length too small Increase STRING[N] to N = max expected chars + 2
Permission denied writing to USB Panel USB path or authentication Verify panel user has write permission to /media/<label>/; check Eject routine

FAQ

How do I call LookupText from a WinCC VBScript on a Comfort Panel?

Invoke LookupText against the runtime tag's value, e.g. SmartTags("PFnumber").LookupText(SmartTags("PFnumber").Value). The function returns the active-language display string from the bound HMI text list.

Why does my CSV show the old alarm text after editing the text list?

The VBScript is still writing a hard-coded literal. Refactor the script to read the text through LookupText (or a paired PLC string) so the text list is the single source of truth.

Can I keep the same error code 30 mapped to different text on five different machines?

Yes. Create one text list per machine (PFError_M1 ... PFError_M5) and select the active list in the script using a MachineID tag. The Openness API can roll out all five lists in one build.

What is the maximum STRING length for a PLC DB string referenced by WinCC?

On S7-1500 optimized blocks, the practical limit is 254 characters per STRING; on legacy DBs it is 254 minus the 2-byte length header. Larger payloads should use WSTRING or a multi-line text block.

Which TIA Portal versions does the Openness API support for text list import?

The Managing alarm text list in PLC and mastercopy library page documents V21. Earlier major versions (V16 through V20) expose the same concepts with version-specific namespace changes; pin the Openness DLL to match the target TIA Portal version.

Back to blog