Resolving WinCC VBScript Math Errors with HMI Tags

David Krause12 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

1. Problem Overview

A common WinCC VBScript task fails on the runtime when an engineer attempts to read two external PLC tags, sum their values, and either write the result into a third internal tag or push it directly to an I/O field on the screen. The symptom is one of three failure modes:

  • Runtime reports "Object required" or "Variable not defined" the first time the script fires.
  • Calculation produces Empty or concatenated string values (e.g. "12" + "3" = "123") instead of the numeric sum 15.
  • Script writes silently to the wrong tag, leaving the target tag unchanged while a source tag is overwritten.

All three modes are caused by the same family of mistakes: missing Dim declarations, missing Set when binding a tag object, writing back to a tag object that was never instantiated, or treating tag values as Variants when VBScript coercion rules produce string concatenation rather than arithmetic.

This reference documents the correct HMIRuntime.Tags pattern for the TIA Portal WinCC Comfort/Professional and WinCC V7.x runtimes, with verified snippets for tag-to-tag addition and I/O field output.

2. Root Cause Analysis

The VBScript runtime in WinCC is the same engine that ships with Windows Script Host (WSH) 5.8, so it inherits VBScript's late-binding, variant-only semantics. The HMIRuntime.Tags object is a custom COM wrapper provided by Siemens that exposes every configured HMI tag as a Tag instance. Three rules govern its correct use:

  1. Bind before reading. HMIRuntime.Tags("name") returns a Tag reference; you must assign it with Set, not with =.
  2. Read explicitly. A bound Tag object does not contain a live process value until .Read is called. Reading .Value without a prior .Read returns the cached or default value.
  3. Write explicitly. Modifying .Value updates an in-memory buffer; the value is not committed to the tag system until .Write is called. Writing to an unbound variable name (e.g. Tag2.Write = calc) raises error 424 "Object required".

Most reported failures are caused by violating rule 1 or rule 3. The original pattern submitted in the source is shown below for reference:

Dim extag1
Dim extag2
Dim calc
extag1 = HMIRuntime.Tags("tag1").Read  ' INCORRECT - default property, no Set
extag2 = HMIRuntime.Tags("tag2").Read  ' INCORRECT
calc   = extag1 + extag2                    ' may concatenate strings
HMIRuntime.Tags("tag2").write = calc        ' INCORRECT - .write is a method, not a property

Each of the four flagged lines violates the binding and write rules above.

3. Required WinCC VBScript Objects and Methods

The following members of the WinCC runtime object model are required. All are documented in the Siemens "WinCC V7 Scripting: VBS for Actions and Procedures" manual, available on the Siemens Industry Online Support portal.

Object / Method Returns Purpose
HMIRuntime.Tags(name) Tag Binds a tag by name. Returns the live Tag object.
Tag.Read Boolean Refreshes .Value from the tag system. Returns success flag.
Tag.Write (optional value) Boolean Writes the current .Value back, or writes the supplied value directly.
Tag.Value Variant Read/write buffer for the tag's process value.
ScreenItems(name) ScreenItem Binds a screen object (I/O field, text field, button).
HMIInputField.OutputValue Variant Drives the displayed value of an I/O field.

Two related topics deserve mention. The Microsoft Scripting documentation defines the Variant subtype rules that VBScript uses; the same rules apply inside WinCC. The TIA Portal help, embedded inside the TIA Portal installation (info -> Help) and mirrored on Siemens Support, lists every event-driven hook (tag trigger, scheduled task, screen event) at which a VBS action can be attached.

4. Solution: Correct Tag-to-Tag Addition

The canonical pattern for reading two external tags, summing them, and writing the result to a third internal tag is shown below. The third tag must be configured in the HMI tag table with Internal connection mode, since the runtime cannot write to a tag whose connection points back to the PLC unless that tag is explicitly writable in the PLC's process image.

' --- VBS for TIA Portal WinCC / WinCC V7.x ---
Option Explicit

Dim extag1, extag2, intag1

Set extag1 = HMIRuntime.Tags("Tag1")
Set extag2 = HMIRuntime.Tags("Tag2")
Set intag1 = HMIRuntime.Tags("Internal_Tag1")

extag1.Read
extag2.Read

intag1.Value = CDbl(extag1.Value) + CDbl(extag2.Value)
intag1.Write

Notes on this snippet:

  • Option Explicit forces every variable to be declared; any undeclared identifier produces error 500, which surfaces immediately rather than silently at runtime.
  • Set is required on every line that binds a Tag object. Dropping it makes the assignment assign the default property (the value), not the object reference.
  • CDbl() coerces each operand to a 64-bit IEEE-754 double. Without the conversion, two values such as "12" and "3" concatenate to "123" because VBScript uses the + operator as string concatenation when both operands are variants of subtype String.
  • The intag1.Write call commits the result. A frequent mistake is to write to intag1.Value = and then call intag1.Read by accident; that refreshes the buffer from the tag system and discards the local edit.

5. Solution: Driving an I/O Field Output

When the goal is to display the sum in an I/O field rather than write it to a third tag, replace the third Set with a ScreenItems binding. The I/O field's OutputValue property must be the configured Output mode (unidirectional) for direct assignment; use the default Input/Output mode only if the operator can also overwrite the value.

Dim extag1, extag2, calc, iofield

Set extag1 = HMIRuntime.Tags("Tag1")
Set extag2 = HMIRuntime.Tags("Tag2")

Set iofield = ScreenItems("IOField_Result")

extag1.Read
extag2.Read

calc = CDbl(extag1.Value) + CDbl(extag2.Value)
iofield.OutputValue = calc

The I/O field name is the Name attribute from the properties pane, not the text label. If the I/O field is on a faceplate or a different screen, the binding must be qualified with the faceplate container or resolved by the container's Find method; in single-screen projects the unqualified name is sufficient.

6. Numeric Coercion: CDbl, CInt, FormatNumber

VBScript stores every variable as a Variant, and the runtime uses the same coercion table that Microsoft documents for VBScript. The + operator's behavior depends on the subtypes of its operands:

Left operand subtype Right operand subtype Result of +
Numeric Numeric Numeric addition
String (digits only) String (digits only) Numeric addition in WinCC V7; string concatenation in legacy WSH 5.6
String String (non-numeric) String concatenation
Empty Numeric Numeric addition (Empty coerces to 0)
Null Numeric Null result (trap error)

For a portable solution, always force numeric coercion at the boundary. The three useful functions are:

  • CDbl(value) – 64-bit double. Best default for sums, products, and divisions.
  • CInt(value) – 16-bit signed integer. Use only for boolean-style or counter tags where overflow is impossible (range -32 768 to +32 767).
  • FormatNumber(value, digits) – rounds to digits decimal places and returns a string. Use only when the result feeds a text property, never a PLC tag, because the string is incompatible with downstream numeric logic.

A defensive idiom often used in the field is the *1 multiplier hack: calc = (extag1.Value + extag2.Value) * 1. The multiplication forces numeric subtype on the result. It works for integers, but it loses precision on values larger than 2^31, so prefer CDbl in production code.

7. Static Text Alternative for Display-Only Output

If the calculated value is only ever displayed, a StaticText object consumes less runtime memory than an I/O field. The I/O field allocates an internal HMIInputField control with both input and output pipelines, plus a tag link; the static text uses only the .Text property.

Dim tf
Set tf = ScreenItems("StaticText_Result")
tf.Text = CStr(CDbl(extag1.Value) + CDbl(extag2.Value))

CStr is mandatory because .Text is a string property; assigning a Double variant triggers a variant-to-string coercion that uses the system's locale, which on a German engineering station produces 3,14 rather than 3.14 and may not match the PLC's expected representation.

8. Diagnostic and Debug Techniques

When the script behaves differently in the simulator and on the panel, or when the panel returns a runtime error, use the following diagnostic sequence.

  1. Enable diagnostics project. In TIA Portal select the HMI device, open Runtime settings -> General, and tick "Start runtime with diagnostics". This opens the ApDiag.exe viewer at runtime startup.
  2. Use HMIRuntime.Trace. Replace the suspicious line with HMIRuntime.Trace "extag1=" & CStr(extag1.Value) & vbCrLf. The trace text appears in the diagnostic output and in the log file under <project>\Logs\<device>\<date>.log. The VBScript trace API is documented in the Siemens WinCC scripting reference.
  3. Tag simulator check. Right-click the tag in the HMI tag table and select "Simulate". A simulated tag ignores the PLC connection and accepts a manual value, which isolates whether the failure is in the script or in the data acquisition layer.
  4. Check acquisition cycle. Tags configured with acquisition mode "On demand" are refreshed only when an action calls .Read. Tags in "Cyclic continuous" or "Cyclic in use" mode are refreshed by the runtime scheduler. If the script runs in a 100 ms scheduled task and the tag acquisition is 1 s, the value read is the one cached at the start of the cycle, not the live value. The acquisition settings are documented in the TIA Portal help topic "Configuring HMI tags".

9. Common Pitfalls and Counter-Examples

The following patterns are syntactically tempting but wrong. Each was a real failure in the field reports that motivated this article.

Pattern Symptom Why it fails
Tag2.write = calc Error 424 "Object required" write is a method, not a property; the assignment target is unresolved.
extag1 = HMIRuntime.Tags("t").Read (no Set) Subsequent .Value is empty Default property binds the value, not the object; the object is discarded.
calc = extag1.Value + extag2.Value with string tags "12" + "3" = "123" VBScript + concatenates when both operands are strings.
intag1.Value = calc without intag1.Write Tag reads old value in the next cycle Assignment to .Value only updates the local buffer.
Reading tags across screen windows via ScreenItems Object not found Use the faceplate container's Find method or pass the tag by reference, not by screen name.

10. Multiplication, Division and Mixed Arithmetic

Once addition is working, the same pattern extends to other operators. Two field-tested cases follow.

Scaled engineering value – convert a raw 16-bit analog input to a 0–10 V reading by multiplication:

Dim raw, scaled
Set raw = HMIRuntime.Tags("AI_Raw")
Set scaled = HMIRuntime.Tags("AI_Scaled_V")
raw.Read
scaled.Value = CDbl(raw.Value) * 10# / 32767
scaled.Write

Ratio with guard against divide-by-zero:

Dim a, b, ratio
Set a = HMIRuntime.Tags("Tag_A")
Set b = HMIRuntime.Tags("Tag_B")
a.Read
b.Read
If CDbl(b.Value) = 0 Then
    HMIRuntime.Trace "Tag_B is zero, ratio skipped" & vbCrLf
    ratio = 0
Else
    ratio = CDbl(a.Value) / CDbl(b.Value)
End If
HMIRuntime.Tags("Tag_Ratio").Write CDbl(ratio)

The trailing CDbl on the Write argument is a defense against an Empty ratio reaching the tag system when the conditional branch is missed.

11. Verification Procedure

After deploying the corrected script, perform the following four-step verification. Each step is observable from the panel itself and requires no PLC modification.

  1. Static check. Open the project in TIA Portal and recompile the HMI device. The "Compile" tab lists any remaining syntax errors. A clean compile confirms the snippet is syntactically valid.
  2. Simulator check. Start the WinCC runtime in the simulator (RT start) and force Tag1 = 10, Tag2 = 32 through the tag table's right-click → "Simulate". Trigger the script (button click, scheduled task, or tag trigger). The destination tag should read 42, not "1032".
  3. Trace check. With HMIRuntime.Trace enabled, confirm that the read values, the coercion, and the write all execute in the order written. The log line will show, for example, intag1.Value=42.0.
  4. Live panel check. On the panel, set the source tags via the control panel test page, then read the destination tag from the diagnostics page. The values must agree with the simulator check.
Safety note. When the destination tag is read by a PLC program (e.g. for a recipe setpoint), verify that the runtime acquisition cycle of the destination tag is shorter than the PLC's read cycle; otherwise the panel will display the new value while the PLC continues to read the old one for up to one acquisition cycle. The acquisition cycle is configured in the HMI tag table under "Acquisition mode" → "Update" / "Cyclic continuous".

12. Performance and Memory Considerations

Each Set obj = HMIRuntime.Tags(name) call performs a name lookup in the runtime's tag dictionary. The lookup is hashed, but in scripts that fire in tight loops (sub-second schedules, fast event triggers), the cost dominates the script. Two optimizations apply:

  • Cache tag objects at the top of the script. When a scheduled task runs every 100 ms, declaring the Set lines once per cycle is fine; declaring them inside a sub-function that runs thousands of times per second is not. Use module-level Dim declarations with Set done once in the script header.
  • Combine .Read and .Write. Tag.Write value (with argument) is faster than assigning Tag.Value = ... and then calling Tag.Write, because the latter is two COM calls and the former is one.

For static calculations, an alternative to VBScript is a C-script or a function block on the PLC side. PLC-side computation offloads work from the panel's ARM or x86 CPU, which can matter on Comfort Panels with the smaller 4-inch and 7-inch displays. The decision is workload-specific and is discussed in the Siemens application note "Comfort Panel Performance Best Practices".

13. Frequently Asked Questions

Why does my VBScript produce "123" when adding 12 and 3 in WinCC?

The two source tags are returning values of subtype String because their PLC source is a string variable or because the tag was configured as type WString/String. Wrap each operand in CDbl(...) to force numeric coercion: calc = CDbl(t1.Value) + CDbl(t2.Value).

What is the difference between Tag2.write = calc and Tag2.Write calc?

Tag2.write = calc uses write as if it were a writable property; it is not. The correct form is the method call Tag2.Write calc, which passes calc as the method's argument. The first form triggers VBScript error 424 "Object required".

Do I need Set when assigning HMIRuntime.Tags(...) to a variable?

Yes. HMIRuntime.Tags returns an object reference. Set obj = HMIRuntime.Tags("Name") binds the object; obj = HMIRuntime.Tags("Name") assigns the default property (the value) and discards the object. Without Set, subsequent obj.Read or obj.Write fail with error 424.

Can I display the calculated value on an I/O field without a third tag?

Yes. Bind the I/O field with Set iofield = ScreenItems("IOField_Result") and assign iofield.OutputValue = calc. Set the I/O field's "Mode" property to "Output" if the operator should not be able to overwrite the value.

Why does the same script work in the simulator but fail on the panel?

Two common causes: the acquisition mode of the source tags differs between simulator and panel (the panel uses "On demand" while the simulator defaulted to "Cyclic continuous"), or the script's Set binding is to a faceplate container that is not instantiated in the runtime. Add HMIRuntime.Trace lines at every Set call to confirm the binding succeeded before the .Read call.

Back to blog