Overview
Siemens WinCC Comfort, WinCC Advanced, and WinCC Professional expose HMI tags to the Runtime scripting engine as SmartTag objects. The most common pattern on a TP700 Comfort Panel is to bind a script to an event (button click, value change, scheduled task) and read or write one of these tags. When only a single tag is involved, the read syntax is identical to the write syntax and works without ceremony. The confusion begins the moment a script has to address a tag whose suffix is not known at compile time — for example Motor_1_RPM, Motor_2_RPM, … Motor_10_RPM — and the suffix has to be built from an integer loop counter.
This reference documents the correct read pattern, explains why a naive SmartTags("Tag") call returns an object reference that cannot be used directly in expressions, and shows loop-based, string-built dynamic tag access. It applies to TIA Portal V15.1 through V20 and covers the documented behavior of the SmartTag object and the HMI tag access page in the official TIA Portal Help.
Prerequisites
- TIA Portal V15.1, V16, V17, V18, V19, or V20 with WinCC Comfort/Advanced or WinCC Professional installed.
- Runtime license: WinCC Comfort for TP700 (and other Comfort Panels) or WinCC Advanced / RT Advanced for PC-based Runtime.
- Comfort Panel (TP700, TP900, TP1200, KP, KTP, or RT Advanced) running firmware matching the TIA Portal version, or a WinCC RT Advanced instance on Windows.
- At least one HMI tag of an internal or external PLC type defined in the project. External tags require a configured connection to the PLC and a reachable CPU.
- The script editor available in the project (Panels → Scripts → VBScripts). The
VBscripting environment is enabled by default on Comfort Panels and RT Advanced.
The SmartTag Object Model
The SmartTags collection is a flat namespace that mirrors the project's HMI tag table. Each item returned by the collection is a SmartTag value-type wrapper, not a true COM object. According to the official TIA Portal V20 reference:
The SmartTag object provides read and write access to the value of the specified process tag. The SmartTag object does not return an object reference.
In practice this means:
| Operation | Syntax | Result type |
|---|---|---|
| Read value | SmartTags("Tag").Value |
Variant (matches tag data type) |
| Write value |
SmartTags("Tag") = 42 or SmartTags("Tag").Value = 42
|
None (assignment) |
| Tag name lookup | SmartTags("MyTag") |
SmartTag wrapper (use .Value to read) |
| Existence test | No direct Exists method — must be wrapped in error handler |
— |
The wrapper has a single primary property, Value, plus a Name property. There is no Quality, Timestamp, or Item accessor at the wrapper level on Panels — those exist only on the PC-based WinCC RT Professional OLE/COM interface, not on the Comfort/Advanced VBScript engine.
Why a Direct Read Fails
The classic symptom reported in the field looks like this:
' Line 17 — does not produce a usable value
Dim v
v = SmartTags("Motor_" & i & "_RPM")
' Line 19 — works
SmartTags("Motor_" & i & "_RPM") = 1500
Line 19 succeeds because the VBScript runtime treats the left-hand side of an assignment as a sink: it locates the SmartTag wrapper, calls the equivalent of PutValue, and discards the wrapper.
Line 17 appears to assign the wrapper to v. Because the SmartTag is not an object reference, the assignment is invalid. The result is either a runtime error (Object required, error 424) or, on some firmware versions, an empty Variant. There is no implicit Value coercion in this assignment context, unlike property access in many other COM objects.
The correct pattern appends .Value explicitly:
Dim v
v = SmartTags("Motor_" & i & "_RPM").Value
This forces the wrapper to evaluate its Value property, returning a normal Variant of the tag's data type. .Value works for both read and write, so the syntax is consistent regardless of direction.
Building Dynamic Tag Names
The VBScript concatenation operator & builds a string at runtime. The tag name passed to SmartTags is a case-insensitive string literal at runtime — the VBScript engine performs a lookup against the HMI tag table at the moment the script executes. This means the string can be assembled dynamically from variables, fixed prefixes, fixed suffixes, and an integer index.
| Component | Example | Notes |
|---|---|---|
| Fixed prefix | "DB09_Cylinders_Y" |
Must match a tag prefix in the HMI tag table |
| Loop index | i |
Convert with CStr(i) if you prefer explicit typing |
| Fixed suffix |
"_PV" or "_RPM"
|
Conventions: _PV = process value, _SP = setpoint, _OP = output |
The full expression becomes:
Dim sName As String
sName = "DB09_Cylinders_Y" & CStr(i)
Dim v As Variant
v = SmartTags(sName).Value
If the index starts at 1 and the project has tags DB09_Cylinders_Y1 through DB09_Cylinders_Y10, the loop iterates 1..10 and v contains the value of the matching tag on each pass.
Complete Loop Example
Place this script on a button's Click event or a scheduled task. It reads ten motor RPM tags and writes the average into an HMI display tag.
' --- SumMotorRPM.vbs ---
Option Explicit
Dim i As Integer
Dim sName As String
Dim dSum As Double
Dim dVal As Double
dSum = 0
For i = 1 To 10
sName = "Motor_" & CStr(i) & "_RPM"
' Read via the .Value property — this is the only correct read pattern
dVal = CDbl(SmartTags(sName).Value)
dSum = dSum + dVal
Next i
SmartTags("Motor_AvgRPM").Value = dSum / 10
Three rules make this robust:
-
Always terminate the read with
.Value. Without it, the assignment todValraisesObject required (424)on firmware versions that strictly enforce the wrapper semantics. -
Use
CStr(i)explicitly. The&operator coerces numbers to strings, but explicit conversion avoids the VBScript empty-value trap wheniis uninitialized. -
Coerce to the target type after read.
CDbl(...),CInt(...), andCStr(...)force the Variant to a deterministic type, which matters when the downstream code uses typed math or string formatting.
User-Defined Type (UDT) Tag Caveats
WinCC V15.1 and later can expose PLC UDTs as structured HMI tags. A UDT tag named Recipe_1 with a member Temperature is accessed as SmartTags("Recipe_1.Temperature").Value. The same dynamic-string rules apply, but with two field-proven constraints:
-
The UDT must be "used" in the project. If a UDT is defined in the PLC and mapped to an HMI tag, but no screen, faceplate, or script references any of its members, the WinCC code generator may strip the members from the HMI tag table. The script then raises
Unknown tag (1901)at runtime. The fix is to bind at least one member to a screen element, even if the element is hidden, or to use the tag in a different script first. -
The member name must be spelled exactly.
SmartTags("Recipe_1.temperature")with a lowercasetfails on panels that have case-sensitive member resolution. Build the string with constants rather than free-form text to avoid case drift.
For Siemens-side UDT guidance, see the official access to HMI tags documentation, which lists the UDT lookup mechanics used by the VBScript engine.
Error Handling
The VBScript engine on Comfort Panels reports tag-related errors through the standard Err object. The relevant error codes are:
| Error number | Meaning | Typical cause |
|---|---|---|
| 424 | Object required | Read a SmartTag without appending .Value
|
| 13 | Type mismatch | Assigned a string Variant to a numeric tag or vice versa |
| 1901 | Unknown tag / HMI tag fault | Tag does not exist in the project, or PLC connection is down |
| 1902 | HMI tag value could not be read | PLC connection lost, area pointer disabled, or quality is Bad |
| 1903 | HMI tag value could not be written | Tag is read-only, or PLC rejects the write (e.g. wrong area) |
A production-quality wrapper:
Function ReadHMITag(ByVal sName As String) As Variant
On Error Resume Next
Dim v As Variant
v = SmartTags(sName).Value
If Err.Number <> 0 Then
' HMI tag lookup failed or PLC disconnected
HMIRuntime.Trace("ReadHMITag(" & sName & ") failed: " & Err.Number & " / " & Err.Description & vbNewLine
ReadHMITag = Null
Else
ReadHMITag = v
End If
On Error Goto 0
End Function
Callers can test IsNull(ReadHMITag("Motor_3_RPM")) and branch accordingly. Tracing the failure to the HMI diagnostic log (or to a permanent log tag) is essential on panels where the diagnostic view is the only post-mortem tool.
Performance Notes for TP700
Comfort Panels run a single-threaded VBScript host. Each SmartTags(...).Value call into an external tag triggers a single PLC read over the configured connection (PROFINET, MPI, or PROFIBUS). Practical limits:
- One read of an external tag on PROFINET: ~5–15 ms on a TP700 at V15.1 firmware.
- One read of an internal tag: sub-millisecond, in-memory.
- Loop of 100 external tags: ~1.5 seconds, during which the HMI thread is blocked. Use a scheduled task with a stagger (e.g. read 10 tags every 100 ms) instead of blocking the main thread for 1.5 s.
If the same data is read frequently, expose it once via a structure tag or use a job-based pattern (set an index, let the PLC populate a buffer, read the buffer).
Tag Naming and Synchronization
After changing tag names in the HMI tag table, recompile the project fully (not incremental) and re-transfer to the panel. Partial transfers can leave the script engine holding a stale tag table that does not include the new names, producing false 1901 errors. The HMI tag access page documents the project transfer prerequisites that the script engine depends on.
Verification Checklist
- Compile the project in TIA Portal — no warnings about unresolved tag references.
- Transfer the project to the TP700 (or start RT Advanced).
- Open the HMI diagnostic viewer (Control Panel → Diagnostics) and start the script.
- Confirm the script log shows the expected tag values for each index in the loop.
- Disconnect the PLC connection and re-run: the script must enter the error branch and not crash the Runtime.
- Reconnect and verify the next loop iteration recovers automatically (no Runtime restart required).
Troubleshooting Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| Write works, read returns empty or 424 | Missing .Value on read |
Append .Value on every read |
| Error 1901 at first loop iteration only | Index off-by-one — tag Motor_0_RPM not defined |
Verify tag table contains the full name range |
| Error 1901 for UDT member | UDT member not generated because no UI element uses it | Bind the UDT member to a hidden IO field or a placeholder screen element |
| Script freezes for several seconds on click | Loop reads many external tags synchronously | Stagger the loop over multiple scheduled tasks or use a buffer tag |
| Read returns stale value after PLC change | Acquisition cycle on the connection is too long | Lower the acquisition cycle in the connection properties or trigger via job mailbox |
| Tag exists, still raises 1901 | Project was not fully recompiled after tag rename | Full compile, full transfer, restart Runtime |
| String tag returns "" instead of value | String tag's initial value is empty, and PLC has not written | Set the tag's initial value in the tag table or check PLC program |
Why does SmartTags("Tag") = value work, but x = SmartTags("Tag") fail?
The SmartTag object is a value-type wrapper, not an object reference. The assignment on the left side of an equation is a sink operation that succeeds silently, but reading the wrapper into a Variant raises error 424 (Object required). Always append .Value when reading: x = SmartTags("Tag").Value.
Can I build a SmartTag name dynamically with a string and an integer index in WinCC VBScript?
Yes. Concatenate the prefix, the index (converted with CStr), and the suffix, then pass the resulting string to SmartTags. Example: SmartTags("Motor_" & CStr(i) & "_RPM").Value. The tag must exist in the HMI tag table at runtime.
What does "_PV" or "_RPM" at the end of a tag name mean in this context?
They are user-defined suffixes, not WinCC keywords. _PV commonly stands for Process Value, _SP for Setpoint, _OP for Output, and _RPM for the engineering unit. The underscores are simply part of the tag name and have no special meaning to the VBScript engine.
Why do UDT members raise "unknown tag" even though the UDT is defined in the PLC?
The WinCC code generator may strip UDT members that no screen or script references. Bind the UDT to a screen element (even a hidden one) or reference one of its members from another script first, then recompile and re-transfer the project.
How do I read an HMI tag without crashing the panel if the PLC connection is down?
Wrap the read in On Error Resume Next, check Err.Number after the read, and branch to a logging or fallback path. HMI tag read errors return numbers in the 1900 range (1901 = unknown tag, 1902 = read failure) on Comfort Panels and RT Advanced.