WinCC Multi-Bit Color Animation: VBScript and C Script Guide

David Krause13 min read
HMI / SCADASiemensTutorial / 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

SIMATIC WinCC screens frequently need a single object whose color encodes a value carried by several PLC bits. A typical case is a process indicator where Bit 0 = running (green), Bit 1 = warning (yellow), Bit 2 = fault (red), and Bit 3 = maintenance (brown). The classic workaround — stacking three or four objects on top of each other and toggling their Display property — works, but inflates the picture with duplicates and forces the operator to maintain overlapping visibility logic.

The standard WinCC scripting toolbox — VBScript, ANSI-C, Dynamic Dialog, and the Status Display — provides four first-class techniques for collapsing a multi-bit input into a single object whose BackColor and ForeColor reflect the current state. This reference documents each technique end-to-end, defines the bit-to-color contract, gives runnable code for WinCC Professional (TIA Portal V16/V17) and WinCC V7.5 SP2, lists the supported color constants, and ends with a verification matrix plus a troubleshooting table that maps common runtime errors to root causes. For background on how WinCC encodes the 24-bit color space, see Color depth on Wikipedia.

Prerequisites

  • SIMATIC WinCC V16 or V17 (WinCC Professional in TIA Portal) or SIMATIC WinCC V7.5 SP2. The VBScript HMIRuntime object is identical across both code paths; the C-script apdefap.h declarations are valid on the WinCC V7.x side, while WinCC Professional uses VBScript as the only native scripting language.
  • An HMI tag of data type DWORD, WORD, or BOOL array that exposes the state bits from the controller. The HMI connection can be an S7-1200/S7-1500 over PROFINET, or a Softnet connection for a simulated PLC.
  • Engineering rights to edit the HMI screens in the Graphics Designer and to enable the Global Script Runtime under "Runtime settings > Scripts".
  • Knowledge of the tag name and the bit ordering convention in the PLC: WinCC reads multi-bit tags the same way the PLC lays them out, with Bit 0 being the least significant bit.
  • Reference: Siemens Industry Online Support — TIA Portal Help, "Working with scripts" chapter, for the official list of scripting object members.
  • Reference: SIMATIC HMI product page for current runtime version and compatibility matrices.
Note on color encoding: WinCC stores colors as a 24-bit BGR long (Blue in the most significant byte, Red in the least significant byte). A literal of 0xFF0000 is therefore blue, not red. C-script color constants such as CO_RED abstract this so you do not have to remember the byte order at runtime.

Bit-to-Color Mapping Architecture

All four techniques share a single mapping contract. Document the contract once in the project header so every script, dynamic dialog, and bitmap set references the same bit positions.

Bit Mask (hex) State BackColor ForeColor Priority
0 0x01 Running 0x00FF00 (green) 0x000000 (black) Lowest
1 0x02 Standby 0x00FFFF (yellow) 0x000000 (black) Low
2 0x04 Warning 0x0000FF (red) 0x00FFFF (yellow) Medium
3 0x08 Fault 0x0000FF (red) 0xFFFFFF (white) High
4 0x10 Maintenance 0x004040 (brown) 0x00FFFF (yellow) Highest

Priority matters. When more than one bit is set, the highest-priority state wins. The code examples below always test the highest-priority bit first and use Exit Sub / return to short-circuit the rest. This avoids the "blinking green over a red fault" symptom that engineers encounter when they write naive left-to-right assignments.

Method 1: C Script with GetTagBit (WinCC V7.x)

The C-script variant is the most compact and runs on every screen object. The header apdefap.h exposes GetTagBit, GetTagDWord, and the color constants CO_RED, CO_GREEN, CO_BLUE, CO_BLACK, CO_WHITE, CO_YELLOW, and so on. Wire the script to the BackColor property of the object; return value is interpreted as a BGR long.

#include "apdefap.h"
long _main(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
    if (GetTagBit("Tag_Fault"))         return CO_RED;     // 0x0000FF
    if (GetTagBit("Tag_Maintenance"))   return CO_DK_GRAY; // 0x004040
    if (GetTagBit("Tag_Warning"))       return CO_YELLOW;  // 0x00FFFF
    if (GetTagBit("Tag_Standby"))       return CO_CYAN;    // 0xFFFF00
    if (GetTagBit("Tag_Running"))       return CO_GREEN;   // 0x00FF00
    return CO_BLACK;
}

Per-object wiring: Right-click the object → Properties → BackColor → Dynamic → C Action. The trigger field accepts either a tag name (cycles on every change) or a fixed cycle (default 2 s). For fastest response, set the trigger to the highest-priority tag with the property "On change". A separate trigger on ForeColor is normally unnecessary: the dynamic dialog trick below handles both colors from one trigger.

Validation in the compiler: Open the script in the C-Editor and press F7 ("Check Syntax"). The V7.x C-Editor flags missing parentheses, undeclared variables, and bad tag names. The script will not be downloaded to the RT until it compiles.

Method 2: VBScript with HMIRuntime (Cross-Version)

VBScript is the only scripting language that works identically in WinCC V7.x and WinCC Professional (TIA Portal V16/V17). Use it when the project will be migrated to TIA Portal later. The script reads a single DWORD alarm tag, masks the bits with the And operator, and assigns RGB triplet literals to the BackColor / ForeColor of the object passed in by the runtime.

Sub IO_Color_ByAlarmBits(Byval obj)
    Dim tagName, val
    tagName = obj.ObjectName & ".ALARM"
    val = HMIRuntime.Tags(tagName).Read
    If (val And 16) <> 0 Then            ' Bit 4 - maintenance (highest priority)
        obj.BackColor = RGB(64, 32, 0)    ' brown
        obj.ForeColor = vbYellow
        Exit Sub
    ElseIf (val And 8) <> 0 Then         ' Bit 3 - fault
        obj.BackColor = vbRed
        obj.ForeColor = vbWhite
        Exit Sub
    ElseIf (val And 4) <> 0 Then         ' Bit 2 - warning
        obj.BackColor = vbYellow
        obj.ForeColor = vbBlack
        Exit Sub
    ElseIf (val And 2) <> 0 Then         ' Bit 1 - standby
        obj.BackColor = vbCyan
        obj.ForeColor = vbBlack
        Exit Sub
    ElseIf (val And 1) <> 0 Then         ' Bit 0 - running
        obj.BackColor = vbGreen
        obj.ForeColor = vbBlack
        Exit Sub
    Else
        obj.BackColor = vbBlack
        obj.ForeColor = vbYellow
    End If
End Sub

Wire the procedure through an event: object properties → Event → Click / Mouse Over, or trigger it from a tag-change event in the Scheduler. The script uses obj.ObjectName & ".ALARM" so each instance of the object reads its own alarm tag by convention — a pattern that scales to hundreds of indicators without parameterization.

For a panel-wide periodic update, register the Sub in the Global Script → Actions → Project Modules and schedule it on a 1-second cycle. In WinCC Professional the equivalent entry point is the "Scheduled tasks" folder of the HMI device.

Performance tip: Wrap HMIRuntime.Tags(tagName).Read in a single read per cycle, not per property. Two scripts on the same tag will each fire their own read; consolidate the mask test into one script and assign both BackColor and ForeColor inside the same call.

Method 3: Dynamic Dialog with Bitwise Formula

Dynamic Dialog avoids custom code altogether by treating the bit pattern as a numeric value. Encode the multi-bit state as a sum of place values: Status = Bit0·1 + Bit1·10 + Bit2·100 + Bit3·1000. The status integer then maps directly to a discrete look-up table inside Dynamic Dialog.

Bit0 Bit1 Bit2 Bit3 Status BackColor (BGR hex) Field Text
0 0 0 0 0 0x000000 Off
1 0 0 0 1 0x00FF00 Run
0 1 0 0 10 0x00FFFF Standby
0 0 1 0 100 0x0000FF Warn
0 0 0 1 1000 0xFF0000 Fault

Open the object → Properties → BackColor → Dynamic Dialog. In the "Formula" field, type:

(Bit0_Tag) + (Bit1_Tag)*10 + (Bit2_Tag)*100 + (Bit3_Tag)*1000

Then define value ranges: 0 / 0..0 → black, 1 / 1..1 → green, 10 / 10..10 → yellow, 100 / 100..100 → red, 1000 / 1000..1000 → blue. Use the Range column rather than the Value column so the dialog accepts a 1-bit-wide window for each state.

Decimal place values (1, 10, 100, 1000) are chosen because they never collide when summed. Hex place values (0x1, 0x10, 0x100, 0x1000) are equivalent and easier to read alongside mask hex. Do not use binary place values (1, 2, 4, 8) for this technique — the place-value trick relies on unique digit positions, while the C/VB scripts rely on bitwise AND, which is what binary place values enable.

Method 4: Status Display with Bitmap Sets

The Status Display is the only built-in object that can change both color and graphics from a single tag value. Configure a Status Display, open Properties → Bitmaps, and add one entry per state. Set the "Status value" to the same integer used in the Dynamic Dialog approach. The runtime swaps the bitmap on every value change without a custom trigger.

  1. Drag a Status Display from the toolbox onto the screen.
  2. Right-click → Configure → Bitmaps. Add a row for each state and bind the desired PNG/BMP to it.
  3. Set "Process" to Status, the integer tag computed from the bit pattern.
  4. For each state, set the "Background color" of the bitmap row to the desired BGR value; WinCC tints the bitmap at runtime.
  5. Set the trigger cycle to "On change" to minimize RT load.

The Status Display is the most compact solution for control panels where the icon itself (a pump, a valve, a fan) carries the state. It does require one bitmap per state, but the runtime memory cost is small because the images are loaded once and swapped by handle.

Method 5: Compound (Custom) Object Layering

If the rest of the picture is built from compound objects, the cleanest way to add multi-bit coloring is to expose the Display property of the colored rectangle through the compound object's interface. Draw three identical rectangles, layer them on top of one another, mark the upper two as hidden by default, select all three, and choose "Create compound object" from the Graphics Designer menu.

  1. Open the compound object in the configuration dialog and expose the Display property of each internal rectangle to the public interface.
  2. Bind each exposed property to its own tag trigger (Tag_Fault → red, Tag_Warning → yellow, Tag_Running → green).
  3. Save the compound object to the library; instances inherit the interface and can be re-bound to different tags per screen.

Compound objects centralize the look-and-feel in one place — change the fill color once, and every instance updates — but they cost an extra picture-level object and force every screen to use the same triggering tags. For panel-wide consistency, use the library; for screen-specific overrides, prefer Method 1 (C script) or Method 2 (VBScript).

WinCC Color Constant Reference

Use the named constants whenever possible. They abstract the BGR byte order and survive theme or version changes. The table below maps the most common constants in WinCC V7.x and WinCC Professional.

Constant BGR Long RGB Equivalent Typical Use
CO_BLACK 0x000000 (0, 0, 0) Default background
CO_WHITE 0xFFFFFF (255, 255, 255) Default foreground
CO_RED 0x0000FF (255, 0, 0) Fault
CO_GREEN 0x00FF00 (0, 255, 0) Running
CO_BLUE 0xFF0000 (0, 0, 255) Information
CO_YELLOW 0x00FFFF (255, 255, 0) Warning
CO_CYAN 0xFFFF00 (0, 255, 255) Standby
CO_MAGENTA 0xFF00FF (255, 0, 255) Manual / Override
CO_DK_GRAY 0x404040 (64, 64, 64) Inactive / Disabled
CO_LT_GRAY 0xC0C0C0 (192, 192, 192) Disabled text
CO_BROWN 0x004040 (64, 32, 0) Maintenance

In VBScript, the same colors are exposed as vbRed, vbGreen, vbBlue, vbYellow, vbBlack, vbWhite, vbCyan, vbMagenta. In WinCC Professional, RGB() returns the same BGR long the runtime expects, so RGB(255, 0, 0) paints red directly.

Verification and Commissioning

  1. Compile check. Open the C-Editor and press F7 for each script. VBScript has no separate compile step, but the WinCC script debugger (Alt+F11) flags syntax errors when you load the picture in the runtime simulator.
  2. Tag simulation. In WinCC V7.x, open "Tag Simulation" from the Tools menu and toggle each bit. In WinCC Professional, use the HMI Simulation table to write directly to the bit tags. Confirm the BackColor of the bound object changes within the configured trigger cycle.
  3. Priority check. Set all four bits simultaneously. Verify the highest-priority color wins. If two colors flicker, the script is missing an Exit Sub / return short-circuit.
  4. Performance check. Open "Performance" in the RT diagnostic dialog. A typical 50-indicator screen with one C script per indicator should consume less than 5% CPU on a Comfort Panel. Above 15% CPU, consolidate the scripts into a single project-module Sub triggered on a tag-change event.
  5. Color-blind check. Toggle the screen through every state and confirm the ForeColor / BackColor combination has at least a 4:1 luminance contrast for operators with deuteranopia. Yellow on green fails this test; switch the standby ForeColor to vbBlack.
  6. Load test. With all indicators cycling once per second, run the RT for 30 minutes and confirm no memory growth in the Windows Task Manager. A leaking script shows up as 1–2 MB of additional memory every cycle.

Troubleshooting Matrix

Symptom Likely Cause Fix
Object stays black even when Bit 0 is set Script is bound to ForeColor instead of BackColor; or the return value is interpreted as RGB instead of BGR Re-bind the trigger to BackColor and use CO_RED or a BGR literal, not an RGB constant
Two colors flicker on screen Two independent scripts both assign to the same property, last-write-wins race Consolidate into a single script that sets BackColor and ForeColor together
Color never changes on a Comfort Panel Global Script Runtime is disabled in the RT settings Open "Runtime settings > Scripts" and enable both C and VB runtimes
C script: "Tag not found" at runtime Tag name is missing the connection prefix, or the tag is in a different channel Open the tag in the tag management dialog and copy the full Connection::TagName form
VBScript: "Object required: HMIRuntime" The Sub is invoked outside an event context (e.g. from a startup script before runtime is fully loaded) Move the call into a "Tag-triggered" action with a valid tag or use the picture-open event
Dynamic Dialog: wrong color for one state Range column overlaps with the next state; e.g. 1..1 defined twice Re-order the ranges from smallest to largest and check the "Value/Range" column types match
Status Display: bitmap is blank The bitmap file is missing from the project folder or the path was absolute Re-import the bitmap, which stores it under the project's GraCS directory with a relative path
Slow screen load (>5 s) on a Basic Panel Too many individual script triggers; the panel executes them sequentially Replace per-object C scripts with a single scheduled global action
Color correct in WinCC Professional, wrong in TIA Portal V17 Project migrated to WinCC Unified, which uses a different API Wrap the legacy code in a compatibility layer or port to the WinCC Unified GraphQL / JavaScript API

Frequently Asked Questions

Why is my 0xFF0000 literal showing blue, not red?

WinCC encodes colors as a 24-bit BGR long. The literal 0xFF0000 sets the blue byte to 0xFF and is therefore blue. Use CO_RED, 0x0000FF, or RGB(255, 0, 0) in VBScript instead.

Which method is the fastest on a Comfort Panel?

Method 4 (Status Display with bitmaps) — the runtime swaps a bitmap handle and never re-evaluates a script. C scripts and VBScript are comparable in performance, but the Status Display wins when the same tag drives both color and graphic.

Can I drive 16 states with this technique?

Yes. The bit-pattern mapping scales to 4 bits (16 states) by extending the place-value formula to Bit0·1 + Bit1·10 + ... + Bit15·10^15, or by using a single integer tag with the state code computed in the PLC. C and VBScript mask the same way with one If per state.

Does the same code work in WinCC Unified?

No. WinCC Unified uses a different API based on JavaScript and the GraphQL event interface. The C/VBScript examples above target WinCC V7.x and WinCC Professional (TIA Portal V16/V17). For Unified, port the logic to a HMIRuntime.SupportedTags subscription in JavaScript.

How do I keep the script readable for the next engineer?

Document the bit-to-color contract once in the project header (see the table above) and reference it by name in every script. Use the CO_RED family of constants instead of hex literals, and place a single If Tag_Fault Then Exit Sub guard at the top of every VB Sub to short-circuit before lower-priority branches run.

Back to blog