TP1500 Comfort HMI: Custom Recipe CSV Management with VBScript

David Krause16 min read
HMI ProgrammingSiemensTutorial / How-to
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

The Siemens SIMATIC TP1500 Comfort panel (6AV2 124-1QC02-0AX0, 15" widescreen TFT, 1280 x 800) running WinCC Comfort / TIA Portal V16 through V18 supports a built-in Recipe object that downloads/uploads data records between the panel's flash memory and the connected controller. In many field scenarios this built-in object is too restrictive: operators cannot freely name a new recipe, the Download to PLC button is fixed in the control, the exported binary .csv and .rdb files use a non-intuitive schema, and audit trails are difficult to embed. This article documents a fully script-driven recipe workflow that uses VBScript on the panel, an external symbolic I/O field for selection, and standard comma-separated-value (CSV) files written to the panel's removable storage. The approach works with any controller exposed to the panel through a tag interface, including the Allen-Bradley SLC 5/04 or SLC 5/05 in the source scenario.

Why a Custom Recipe Implementation?

WinCC Comfort's standard Recipe object provides automatic data record management, but the following constraints frequently push integrators toward a custom solution:

  • Recipe names are bound to the engineering project and cannot be created at runtime by the operator.
  • The Save, Load, Download, and Delete commands are hard-coded to toolbar buttons and cannot be hidden per user role.
  • The exported record file uses a fixed binary format that shop-floor personnel cannot open in Excel without re-import through the HMI.
  • Versioning, time-stamps, operator IDs, and CSV exports must be appended manually.

A VBScript-driven workflow on the TP1500 Comfort sidesteps all four constraints because the script layer is granted unrestricted access to the HMI file system, tags, and the symbolic I/O field text list.

Prerequisites

Item Requirement
Engineering software TIA Portal V16, V17, or V18 with WinCC Comfort/Advanced installed
Runtime TP1500 Comfort firmware V16.0.0.0 or higher (panel image package matches TIA Portal version)
Storage Industrial SD card (e.g., Siemens 6AV2 181-2AA10-0AA0) inserted in the panel's X50 slot, or USB stick on X60
Controller Any PLC exposed to the panel through tags. Tested with Allen-Bradley SLC 5/05 over EtherNet/IP via the Rockwell RSLinx Classic OPC tunnel, and directly with the native Allen-Bradley Ethernet/IP driver introduced in TIA Portal V17 SP1.
Operator authorization WinCC user group with rights to use VBScript (default: group "Administrator" or group with "Operating" right for the relevant screens)
Transfer WinCC Project Download to the panel with "Start runtime after transfer" enabled

System Architecture

The figure below shows the runtime data flow. Symbolic I/O fields on the TP1500 read their text list from a VBScript that enumerates files in \Storage Card SD\Recipes; pressing Save writes a CSV row built from the HMI tag values back to the same directory, and pressing Load reverses the path.

PLC SLC 5/05 HMI Tags Recipe_*, Cmd_* TP1500 Comfort Symbolic I/O Field VBScript Runtime File System (SD) \Storage Card SD\Recipes\RecipeName_YYYYMMDD_HHMMSS.csv

PLC Tag Structure (SLC 5/05 Side)

The SLC 500 exposes a contiguous block of integer and float registers that hold one recipe record. A common allocation for a 12-element recipe is shown in the table below. Tag names are mapped into the WinCC tag table using the Allen-Bradley Ethernet/IP driver; an alternative is to publish the same data through RSLinx Classic as OPC DA items.

WinCC Tag PLC Address (SLC 5/05) Data Type Description
Recipe_Setpoint_01 N7:0 INT Process setpoint #1
Recipe_Setpoint_02 N7:1 INT Process setpoint #2
Recipe_Setpoint_03 N7:2 INT Process setpoint #3
Recipe_Setpoint_04 N7:3 INT Process setpoint #4
Recipe_Setpoint_05 N7:4 INT Process setpoint #5
Recipe_Setpoint_06 N7:5 INT Process setpoint #6
Recipe_Flow_SP F8:0 REAL Flow setpoint (liters/min)
Recipe_Temp_SP F8:1 REAL Temperature setpoint (°C)
Recipe_Pressure_SP F8:2 REAL Pressure setpoint (bar)
Recipe_Duration_SP F8:3 REAL Cycle time (s)
Recipe_BatchID N7:10 DINT Batch identifier
Recipe_Operator ST14:0 (20 chars) STRING Operator logon name
Cmd_LoadRecipe B3:0/0 BOOL One-shot load from CSV
Cmd_SaveRecipe B3:0/1 BOOL One-shot save to CSV
Cmd_DeleteRecipe B3:0/2 BOOL One-shot delete from SD
Status_RecipeLoaded B3:1/0 BOOL Plc ack after successful load

All recipe tags are configured in WinCC with the same acquisition cycle (1 s) and are pointed to a controller connection named "PLC_SLC5_05". Boolean commands use the Edge-triggered acquisition setting to avoid double execution on a sticky bit.

HMI Tag Configuration

Beyond the controller tags, the following local HMI tags are required. They live only on the panel and are not propagated to the SLC.

Name Type Length Use
Local_RecipeName WSTRING 64 Current selected recipe name (text field input)
Local_NewRecipeName WSTRING 64 Operator-entered name for a brand-new recipe
Local_FileList WSTRING 4096 Multi-line string populating the symbolic I/O field
Local_RecipeCount INT 1 Number of CSV files in the recipe folder
Local_StatusText WSTRING 128 Display feedback ("Saved", "File exists", etc.)
Local_Timestamp DATE_AND_TIME 1 Time-stamp written into the CSV row
Const_RecipeDir WSTRING 256 Constant "\Storage Card SD\Recipes\"
Const_CsvExt WSTRING 8 Constant ".csv"
Path syntax: Comfort panels accept both \Storage Card SD\ and /Storage Card SD/. The back-slash form is the WinCC convention used by HMIRuntime.FileSystem in V16+ projects. Substitute \USB Storage Device\ if you intend to plug a USB stick into port X60 instead of using the SD slot X50.

File System Layout on the TP1500

Create the recipe directory once during commissioning. The WinCC file-system object will not auto-create nested paths, so a one-line Project initialization script on the Start event of the recipe screen ensures the directory exists:

Set fs = CreateObject("Scripting.FileSystemObject")
If Not fs.FolderExists(Const_RecipeDir) Then fs.CreateFolder(Const_RecipeDir)

After the first power-up the panel contains the following structure:

\Storage Card SD\
  ├─ Recipes\
  │  ├─ Recipe_A_20240117_083012.csv
  │  ├─ Recipe_A_20240118_142105.csv
  │  ├─ Recipe_B_20240117_090014.csv
  │  └─ header.txt   <-- optional human-readable description

Each .csv file is a single text line terminated by CRLF, which keeps parsing trivial and survives Excel re-imports. Header definitions live in a separate header.txt to avoid duplicating the schema inside every record.

CSV File Format

Use UTF-8 encoding without BOM to maximise compatibility with other HMI tools and standard Excel. The schema is:

RecipeName;Timestamp;OpName;SP1;SP2;SP3;SP4;SP5;SP6;Flow;Temp;Pressure;Duration;BatchID
Recipe_A;2024-01-17 08:30:12;alice;120;130;140;150;160;170;42.5;78.2;3.10;90.0;77821

Use the semicolon as a separator because Excel for European locales treats a comma as the decimal symbol; the semicolon removes ambiguity in TIA Portal V17/V18 runtime exports. Each line must be terminated with vbCrLf (0x0D 0x0A) on the panel side so the file is recognized by the file system as text and not binary.

Encoding reminder: If the operator logs in with a non-ASCII name, set FileSystem.CreateObject with the optional Unicode flag in VBScript. In WinCC V18 the WriteFile method accepts a third parameter: HMIRuntime.FileSystem.WriteFile sPath, sContent, True writes the buffer as UTF-16 LE, which is the panel's native encoding.

VBScript Core Library

Place the following functions in the project's Scripts container so they can be called from any screen:

ListRecipes() — populates the symbolic I/O field

Sub ListRecipes()
    Dim fs, f, fld, lst, p
    p = SmartTags("Const_RecipeDir")
    Set fs = CreateObject("Scripting.FileSystemObject")
    If Not fs.FolderExists(p) Then fs.CreateFolder(p)
    Set fld = fs.GetFolder(p)
    lst = ""
    Dim cnt
    cnt = 0
    For Each f In fld.Files
        If LCase(Right(f.Name, 4)) = ".csv" Then
            lst = lst & f.Name & vbCrLf
            cnt = cnt + 1
        End If
    Next
    SmartTags("Local_FileList") = lst
    SmartTags("Local_RecipeCount") = cnt
End Sub

SaveRecipe() — writes a new CSV row

Sub SaveRecipe()
    Dim sName, sFile, sLine, sTs
    sName = SmartTags("Local_NewRecipeName")
    If Len(sName) = 0 Then
        SmartTags("Local_StatusText") = "Enter a recipe name first"
        Exit Sub
    End If
    sTs  = 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)
    sFile = SmartTags("Const_RecipeDir") & sName & "_" & sTs & ".csv"
    sLine = sName & ";" & sTs & ";" & SmartTags("Recipe_Operator") & ";" _
          & SmartTags("Recipe_Setpoint_01") & ";" _
          & SmartTags("Recipe_Setpoint_02") & ";" _
          & SmartTags("Recipe_Setpoint_03") & ";" _
          & SmartTags("Recipe_Setpoint_04") & ";" _
          & SmartTags("Recipe_Setpoint_05") & ";" _
          & SmartTags("Recipe_Setpoint_06") & ";" _
          & SmartTags("Recipe_Flow_SP") & ";" _
          & SmartTags("Recipe_Temp_SP") & ";" _
          & SmartTags("Recipe_Pressure_SP") & ";" _
          & SmartTags("Recipe_Duration_SP") & ";" _
          & SmartTags("Recipe_BatchID") & vbCrLf
    Dim fso
    Set fso = CreateObject("Scripting.FileSystemObject")
    If fso.FileExists(sFile) Then
        SmartTags("Local_StatusText") = "File already exists"
        Exit Sub
    End If
    Dim ts
    Set ts = fso.CreateTextFile(sFile, True, False)   ' overwrite=False, unicode=False
    ts.Write sLine
    ts.Close
    SmartTags("Local_StatusText") = "Saved " & sName
    ListRecipes
End Sub

LoadRecipe() — pushes CSV values back into tags

Sub LoadRecipe()
    Dim sName, sFile, sLine, p, arr
    sName = SmartTags("Local_RecipeName")
    If Len(sName) = 0 Then
        SmartTags("Local_StatusText") = "Pick a recipe from the list"
        Exit Sub
    End If
    sFile = SmartTags("Const_RecipeDir") & sName
    Dim fso
    Set fso = CreateObject("Scripting.FileSystemObject")
    If Not fso.FileExists(sFile) Then
        SmartTags("Local_StatusText") = "Recipe file not found"
        Exit Sub
    End If
    Dim ts
    Set ts = fso.OpenTextFile(sFile, 1)   ' 1 = ForReading
    sLine = ts.ReadLine
    ts.Close
    arr = Split(sLine, ";")
    SmartTags("Recipe_Setpoint_01") = CInt(arr(3))
    SmartTags("Recipe_Setpoint_02") = CInt(arr(4))
    SmartTags("Recipe_Setpoint_03") = CInt(arr(5))
    SmartTags("Recipe_Setpoint_04") = CInt(arr(6))
    SmartTags("Recipe_Setpoint_05") = CInt(arr(7))
    SmartTags("Recipe_Setpoint_06") = CInt(arr(8))
    SmartTags("Recipe_Flow_SP")    = CSng(arr(9))
    SmartTags("Recipe_Temp_SP")    = CSng(arr(10))
    SmartTags("Recipe_Pressure_SP")= CSng(arr(11))
    SmartTags("Recipe_Duration_SP")= CSng(arr(12))
    SmartTags("Recipe_BatchID")    = CLng(arr(13))
    SmartTags("Cmd_LoadRecipe")    = True          ' pulse to PLC
    SmartTags("Local_StatusText")  = "Loaded " & sName
End Sub

DeleteRecipe() — removes a file from the SD card

Sub DeleteRecipe()
    Dim sName, sFile
    sName = SmartTags("Local_RecipeName")
    If Len(sName) = 0 Then Exit Sub
    sFile = SmartTags("Const_RecipeDir") & sName
    Dim fso
    Set fso = CreateObject("Scripting.FileSystemObject")
    If fso.FileExists(sFile) Then
        fso.DeleteFile sFile, True
        SmartTags("Local_StatusText") = "Deleted " & sName
    End If
    ListRecipes
End Sub

ExportToUSB() — copies all CSVs to an external USB stick

Sub ExportToUSB()
    Dim fso, src, dst, f
    Set fso = CreateObject("Scripting.FileSystemObject")
    src = SmartTags("Const_RecipeDir")
    dst = "\USB Storage Device\Recipes_" & Replace(Date, "/","-") & "\"
    If Not fso.FolderExists(dst) Then fso.CreateFolder(dst)
    For Each f In fso.GetFolder(src).Files
        If LCase(Right(f.Name,4)) = ".csv" Then
            fso.CopyFile f.Path, dst & f.Name, True
        End If
    Next
    SmartTags("Local_StatusText") = "Exported to " & dst
End Sub

Symbolic I/O Field Configuration

On the recipe screen, drop a Symbolic I/O field configured as Output with Text list mode Variable. Bind the text list source to Local_FileList and the index value to Local_RecipeIndex. The field will display every file name on its own row; tapping a row populates Local_RecipeName via a Change value event that calls Trim(Mid(Local_FileList, (idx-1)*lineLen, lineLen)). The split/line-length helper is shown below.

Sub PickFromList()
    Dim idx, lines, s
    idx = SmartTags("Local_RecipeIndex")
    lines = Split(SmartTags("Local_FileList"), vbCrLf)
    If idx > 0 And idx - 1 <= UBound(lines) Then
        SmartTags("Local_RecipeName") = lines(idx - 1)
    End If
End Sub
Token counter: The Symbolic I/O field's Items per line setting must equal 1 so the Selection index increments by one row per tap. Avoid mapping the index directly to a tag of type INT when the list exceeds 32767 entries (VBScript line counter overflow); for a TP1500 with 32 GB SD the practical cap of ~200 000 CSV files is far beyond normal use, so the default INT range is safe.

Step-by-Step Implementation

  1. Open the TIA Portal project that contains the TP1500 Comfort device. Confirm the HMI device firmware matches the engineering version (e.g., 18.0.0.0 for TIA V18). Mismatched firmware is the leading cause of "Object not found" runtime errors on VBScript.
  2. Add the controller connection: in Devices & Networks connect the TP1500 to the SLC 5/05 CPU. For an SLC 5/05 on EtherNet/IP choose the Allen-Bradley Ethernet/IP driver (TIA V17 SP1+). For an SLC 5/04 on DF1 you must add a third-party gateway (e.g., HMS Anybus X-gateway) and a generic Modbus TCP coupling, because the Comfort panel has no native DF1 port.
  3. Create the local tags listed in HMI Tag Configuration. Right-click HMI Tags > Add new tag, set the data type, and tick Local tag to keep them on the panel side.
  4. Map the SLC tags: open HMI Tags > Default tag table and add a tag for every row in the SLC allocation table. Use the Connection column to bind the tag to the controller connection. For Allen-Bradley addresses use the syntax N7:0, F8:0, B3:0/0 directly, or the symbolic alias exposed by RSLinx.
  5. Create the recipe folder on the SD card by inserting the SD card in a PC, mounting it, and creating \Recipes at the root. Re-insert the card into the panel before compiling.
  6. Insert the VBScript functions: in the project tree select Scripts > VBScripts > Add new and paste the ListRecipes, SaveRecipe, LoadRecipe, DeleteRecipe, ExportToUSB, and PickFromList subroutines above.
  7. Add a new screen titled Recipe_Management. Drop a Symbolic I/O field, three text I/O fields (recipe name, new name, status), and four buttons (Refresh, Save, Load, Delete, plus an Export USB button).
  8. Wire the events:
    • Button Refresh → Click → VBScript ListRecipes
    • Button Save → Click → VBScript SaveRecipe
    • Button Load → Click → VBScript LoadRecipe
    • Button Delete → Click → VBScript DeleteRecipe
    • Button Export USB → Click → VBScript ExportToUSB
    • Symbolic I/O field → Change → VBScript PickFromList
    • Screen Loaded → VBScript that creates the directory and calls ListRecipes
  9. Compile and download: click Compile > Software (rebuild all) and transfer the WinCC project to the panel over Ethernet or USB. Confirm that the HMI connection to the SLC 5/05 reports Connected in the diagnostics screen.
  10. Validate the file-system permissions: WinCC Comfort V16+ requires the project to be configured with File system access enabled. In the project tree, open Runtime settings > Services > File system and tick Allow access to the SD card and Allow access to USB storage. Without this, the file-system object throws Permission denied on the first CreateTextFile call.

Verification

Run through the following acceptance test on the live panel:

  1. Touch Refresh. The symbolic I/O field lists any pre-existing CSV files. With a freshly formatted SD card the field should be empty and the status text should display "0 recipes".
  2. Enter Recipe_A in the new-name field, touch Save. Verify with a PC that \Storage Card SD\Recipes\Recipe_A_*.csv exists and contains exactly one CRLF-terminated line.
  3. Modify one setpoint (e.g., Recipe_Temp_SP), touch Load, and confirm that the value written to the SLC matches the CSV row. The SLC input image at F8:1 should update within one controller scan.
  4. Touch Refresh again — the new file name must appear in the list.
  5. Insert a USB stick and touch Export USB. The destination folder on the stick must contain the same CSV files.
  6. Cycle the panel power. After the restart the symbolic I/O field should be repopulated automatically because the screen's Loaded event triggers ListRecipes.
Audit-trail extension: Add a WinCC Audit option (separate licence 6AV2 107-4GA00-0AA0) to capture every script call with operator name, timestamp, and the recipe file affected. The audit record is written to a separate *.log on the SD card and survives the CSV export step.

Troubleshooting Matrix

Symptom Likely Cause Remediation
Symbolic I/O field shows nothing Scripting event fires before tag is initialised; ListRecipes not called on screen load Wire the screen's Loaded event to ListRecipes; verify tag length of Local_FileList is at least 4096 chars
"Permission denied" on Save File-system access disabled in runtime settings Enable File system > Allow access to SD card in the project, recompile, redownload
CSV saved but values are 0 in PLC Load path missing leading slash or trailing extension Set Const_RecipeDir to \Storage Card SD\Recipes\ with back-slashes and the trailing separator
Setpoint visible on HMI but not in SLC Tag acquisition mode is set to Cyclic continuous with a slow cycle Switch HMI tags to Cyclic on demand and write them from the VBScript, or change the cycle to 250 ms
Recipe name contains non-ASCII chars and file is empty Default text-file mode is ANSI, UTF-8 is required Use CreateTextFile(path, True, True) to force Unicode; the operator name is preserved
SD card corruption after 5 000+ saves File system uses FAT32 with no wear-levelling Replace the SD card with an industrial SLC-grade card (Siemens 6AV2 181-2AA10-0AA0 rated 100 000 P/E cycles) and rotate monthly
Panel cannot reach SLC tags over EtherNet/IP Driver requires TIA Portal V17 SP1 Update 4 or higher Update the engineering project, or fall back to RSLinx OPC tunnel
Operator cannot find the saved file via FTP FTP is disabled by default on Comfort panels Enable Runtime settings > Services > FTP and create a read-only user for download

Performance and Storage Notes

A typical recipe record of 14 values at 32 bytes per line occupies ~3.5 kB after FAT32 cluster allocation. The TP1500's internal flash reserves ~30 MB for the runtime, leaving the full SD capacity (up to 32 GB) for recipes. At 1 000 saves per shift, one year of operation accumulates ~3.2 GB — well below the card's endurance threshold when an industrial card is used.

VBScript execution on the panel is single-threaded; the longest call in this design is the file write at <5 ms for a 1 kB CSV. The symbolic I/O field refresh is bounded by Local_FileList size and is therefore O(n) where n is the recipe count. For n > 500, switch to a paginated list driven by a Slider widget that updates the Local_FileList slice on demand.

Security and Authorisation

Tie the Save and Delete buttons to a WinCC user group with the Manage recipes authorisation level. WinCC Comfort V18 supports per-button visibility based on the active user; the VBScript can additionally reject the call with HMIRuntime.BaseScreenName to harden the flow against script injection from a remote maintenance session. All recipes are timestamped with the operator's WinCC logon name from Recipe_Operator, which is automatically supplied by the Current user system tag.

Field-Commissioning Checklist

  • ✓ Project compiles without VBScript syntax warnings
  • ✓ File-system access enabled in runtime settings
  • ✓ SD card formatted as FAT32 with 32 kB cluster size
  • ✓ Symbolic I/O field token count matches the operator's expectation
  • ✓ PLC tags confirmed as Good in Diagnostics > Connections
  • ✓ Save/Load/Delete tested with two distinct recipes
  • ✓ Power-cycle test: recipes reload automatically
  • ✓ FTP export tested and password-protected
  • ✓ Audit log reviewed and timestamp format validated

How do I create a new recipe name from the TP1500 runtime and save it to CSV?

Add a WSTRING tag Local_NewRecipeName bound to a text I/O field. Wire a Save button to a VBScript that concatenates the name, a timestamp, and the current tag values into a CRLF-terminated string, then calls CreateObject("Scripting.FileSystemObject").CreateTextFile against \Storage Card SD\Recipes\<name>_<ts>.csv. The recipe name is fully operator-defined.

How do I populate a symbolic I/O field with the list of saved recipes?

Use a VBScript that iterates GetFolder(Const_RecipeDir).Files, appends each .csv name separated by vbCrLf into Local_FileList (WSTRING 4096), and binds the symbolic I/O field's Text list to that tag. The selection index drives Local_RecipeName via a Change event script.

Can the saved CSV be opened directly in Microsoft Excel?

Yes. Use UTF-8 encoding, a semicolon as the delimiter, CRLF line termination, and a single header line stored separately. The resulting file opens in Excel as a single column-and-row table and can be re-imported into another HMI tool that supports CSV recipe import.

How do I copy recipes from the panel's SD card to a USB stick for archival?

Trigger a VBScript that uses Scripting.FileSystemObject to enumerate \Storage Card SD\Recipes, create a date-stamped folder under \USB Storage Device\, and call CopyFile for every .csv. Enable USB storage access in the runtime settings first.

Why does the SLC 5/05 not receive the loaded recipe values?

Verify the HMI connection is Connected in the panel's Diagnostics > Connections view. Confirm the tags are not marked Local in the WinCC tag table, that the acquisition cycle is at most 500 ms, and that the symbolic I/O field binds to a controller tag rather than an internal one. For DF1-connected SLC 5/04 CPUs you need a Modbus-TCP-to-DF1 gateway because the TP1500 has no native DF1 port.

Back to blog