WinCC Global Script: Routing Sensor Tags Between Two PLCs

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: Using WinCC as a Tag Bridge Between Two PLCs

SIMATIC WinCC is a supervisory control and data acquisition (SCADA) and human-machine interface (HMI) system from Siemens. In a typical plant, each controller (SIMATIC S7-1200, S7-1500, S7-300/400, or ET 200SP) holds the variables for its own island, and the HMI reads them for visualization. A frequent field request, however, is to drive a final-control element on PLC B from a sensor on PLC A when no direct PLC-to-PLC link (PUT/GET, Profinet I-Device, OPC UA server method) is available, available quickly, or approved by the network administrator.

The pattern in this article routes an ultrasonic level sensor (ULS) reading on PLC A to a pump start/stop command on PLC B by way of a WinCC Global Script. The HMI acts as a "transparent bridge": a periodic trigger reads the ULS tag from PLC A, evaluates a threshold with hysteresis, and writes the resulting boolean to a tag on PLC B. The technique is generic — any source value (level, pressure, flow, temperature) can replace the ULS reading, and any boolean/integer command (pump, valve, heater) can replace the pump output.

Safety notice. Routing control decisions through an HMI is acceptable for non-safety, supervisory, and process-conditioning tasks (cooling fans, secondary pumps, dosing top-ups). It is not acceptable as a substitute for a SIL-rated path. Hard-wired safety interlocks, F-CPU PROFIsafe, or a dedicated safety PLC must always be in the loop for emergency-stop, overfill, dry-run, or over-pressure protection.

When to Use This Pattern (and When Not To)

Use the HMI-as-bridge pattern when all of the following are true:

  • Direct PLC-to-PLC communication (S7 PUT/GET, Profinet I-Device, open IE communication) is blocked, undocumented, or pending a project change.
  • The response time can tolerate the WinCC update cycle (default 1 s, minimum 250 ms in V7.x; configurable down to 100 ms in WinCC Unified V20).
  • The controlled equipment has its own local hard-wired interlock (thermal overload, dry-run probe, level switch).
  • The HMI server is in redundant operation or has a documented fallback.

Do not use this pattern for:

  • Safety instrumented functions (SIF) at SIL 1 or higher — use a F-CPU with PROFIsafe.
  • Hard real-time motion or coordinated drives (use Profinet IRT or Profibus DP).
  • Functions that must continue to operate if the HMI server is offline (use direct PLC-PLC communication).

Prerequisites

Item Specification
WinCC version WinCC V7.4 SP1 or later, or WinCC V8.0 / V8.1 (TIA-based Comfort/Professional), or WinCC Unified V17/V18/V20
Licensing WinCC RT (128 / 512 / 2048 / 8192 PowerTags), or RT Professional (V8.x), or Unified RT (V17+)
PLC A (sensor) SIMATIC S7-1200 (FW 4.2+), S7-1500, or ET 200SP CPU; project must expose the ULS raw value to WinCC
PLC B (pump) SIMATIC S7-1200/1500/300/400; must have a writable tag (e.g. DB20.DBX0.0) for the pump command
Network Ethernet (Profinet) on a common subnet with TCP/IP routing; the HMI must reach both PLCs
Channel driver SIMATIC S7-1200/1500 Channel (preferred), or OPC UA client to a S7-1500 OPC UA server
Engineering tool WinCC Explorer (V7/V8) or TIA Portal with HMI configuration (V15.1+)

System Architecture and Data Flow

The data flow is strictly one-way at the script boundary. The HMI reads from PLC A and writes to PLC B on a fixed cadence.

  1. PLC A scales the ULS 4–20 mA signal to a level value (m) and stores it in a data block (e.g. DB50.DBD0 as REAL).
  2. WinCC has a configured external tag ULS_Level_m (REAL, length 4 bytes) pointing to DB50.DBD0 via the S7 channel.
  3. A Global Script (VBScript) is scheduled with a 1-second trigger.
  4. Each trigger tick: the script reads ULS_Level_m, compares it with a configured threshold (with hysteresis), and computes a boolean command 0 (stop) or 1 (start).
  5. The script writes the boolean to Pump_Command_HMI, an external tag in WinCC that is mapped to DB20.DBX0.0 on PLC B.
  6. PLC B applies its own local logic (run permissive, motor contactor feedback, VFD enable) before energising the pump.
Heartbeat awareness. If the WinCC server stalls, the last-written value remains on Pump_Command_HMI. PLC B should include a watchdog that trips the pump to a safe state if the HMI command does not refresh within a defined window (e.g. a 5-second timer reset on each valid write).

Step 1: Configure the External Tags

Open WinCC Explorer and create two external tags under the SIMATIC S7-1200/1500 channel.

WinCC tag PLC Address Data type Length Direction
ULS_Level_m PLC A DB50.DBD0 FLOAT (REAL) 4 B read-only
Pump_Command_HMI PLC B DB20.DBX0.0 BOOL 1 bit read/write

Also create three internal tags for threshold, hysteresis, and last-command memory:

  • ULS_Threshold_m — FLOAT, initial value 2.50 (pump trips off at 2.50 m)
  • ULS_Hysteresis_m — FLOAT, initial value 0.10 (pump re-arms 0.10 m below threshold)
  • Pump_LastCommand — BOOL, initial value 0

Tag settings in the WinCC Tag Management dialog:

  1. Right-click → Add New Tag, name it ULS_Level_m.
  2. Set Type = External tag, select the SIMATIC S7-1200/1500 Channel connection that targets PLC A.
  3. Enter address DB50,DBD0, data type Float 32-bit IEEE 754.
  4. Repeat for Pump_Command_HMI against the connection to PLC B, address DB20,DBX0.0, data type Binary Tag.

Step 2: Verify Tag Communication with the Channel Diagnostics

Before adding any scripting, confirm the tags are live:

  1. In WinCC Explorer, right-click the channel and select Channel Diagnostics.
  2. Watch the connection state to PLC A and PLC B. Green = connection established, yellow = establishing, red = error.
  3. Open Tag Simulator or a temporary I/O field bound to ULS_Level_m in Graphics Designer.
  4. Force a value into DB50.DBD0 on PLC A using a watch table in TIA Portal and verify it appears on the HMI faceplate within the configured update time.

Step 3: Build the Global Script

Open Global Script → VBS Editor in WinCC Explorer. Create a new action, paste the following routine, and save it as ULS_PumpBridge.

Option Explicit

Function action
    ' --- Configuration constants (WinCC internal tags) ---
    Const TAG_LEVEL   = "ULS_Level_m"           ' REAL from PLC A
    Const TAG_THRESH  = "ULS_Threshold_m"       ' REAL, internal
    Const TAG_HYST    = "ULS_Hysteresis_m"      ' REAL, internal
    Const TAG_LASTCMD = "Pump_LastCommand"      ' BOOL, internal
    Const TAG_PUMP    = "Pump_Command_HMI"      ' BOOL to PLC B
    Const TAG_STATUS  = "HMI_BridgeStatus"      ' WORD, internal, 0=OK 1=Stale 2=Error

    Dim tLevel, tThresh, tHyst, tLast, tPump, tStat
    Dim level, threshold, hysteresis, lastCmd, pumpCmd, status

    status = 0

    Set tLevel  = HMIRuntime.Tags(TAG_LEVEL)
    Set tThresh = HMIRuntime.Tags(TAG_THRESH)
    Set tHyst   = HMIRuntime.Tags(TAG_HYST)
    Set tLast   = HMIRuntime.Tags(TAG_LASTCMD)
    Set tPump   = HMIRuntime.Tags(TAG_PUMP)
    Set tStat   = HMIRuntime.Tags(TAG_STATUS)

    If tLevel.Read = 0 And tThresh.Read = 0 And tHyst.Read = 0 And tLast.Read = 0 Then
        level      = tLevel.Value
        threshold  = tThresh.Value
        hysteresis = tHyst.Value
        lastCmd    = tLast.Value

        ' --- Hysteresis decision logic ---
        If level >= threshold Then
            pumpCmd = 0                  ' high level: stop
        ElseIf level < (threshold - hysteresis) Then
            pumpCmd = 1                  ' recovered: start
        Else
            pumpCmd = lastCmd             ' in dead-band: hold
        End If

        ' --- Write to PLC B ---
        tPump.Value = pumpCmd
        tPump.Write

        ' --- Persist state ---
        tLast.Value = pumpCmd
        tLast.Write

        ' --- Status ---
        tStat.Value = status
        tStat.Write
    Else
        ' QualityCode <> 0 on any tag: signal stale and revert to safe
        tStat.Value = 1
        tStat.Write
        tPump.Value = 0                 ' safe: stop pump
        tPump.Write
    End If
End Function

Line-by-line notes

  • Option Explicit forces every variable to be declared, eliminating a common source of Type mismatch runtime errors.
  • The Read method returns the WinCC quality code (0 = Good). If any of the four reads returns non-zero, the script assumes the HMI lost contact with a PLC and forces the pump to the safe state (0 = stop).
  • The hysteresis dead-band prevents chattering when the surface ripples around the setpoint.
  • HMIRuntime.Tags(...).Write performs an immediate write; for higher throughput, wrap multiple writes in Tags.Item(...).Write with a single HMI variable list.
Quality codes reference. WinCC returns 0 (Good), 1 (Bad), 2 (Uncertain), or higher vendor-specific values from Read. Always check this value before acting on .Value, otherwise a stale tag will silently propagate bad data into PLC B.

Step 4: Configure the Trigger

Global Scripts in WinCC V7/V8 execute on a defined trigger. The choice of trigger directly controls the response time of the bridge.

  1. Open the action's Properties dialog and select the Trigger tab.
  2. Add a Time trigger. The minimum reliable value is 1 second; values below 500 ms can starve the script runtime queue under heavy graphics load.
  3. Optionally add a Tag trigger on ULS_Level_m with a change threshold (e.g. 0.05 m). This couples execution to actual process change and reduces CPU load.
  4. Save the action. The trigger editor shows the next fire time and current period.
Trigger type Recommended setting Use case
Time (cyclic) 1 s Slow processes (tank level, sump)
Time (cyclic) 250 ms Fast processes, only if HMI CPU is < 60 %
Tag change Threshold 0.05 m on ULS_Level_m Reduces work when level is stable
Hotkey User action Manual override / engineering test

Step 5: Runtime and Startup Settings

  1. In WinCC Explorer, open Computer → Properties → Startup tab.
  2. Enable Global Script Runtime. Without this checkbox, the VBS actions never execute, even though the editor compiles them.
  3. Add the action ULS_PumpBridge to the Startup list if you want it to run once at WinCC startup (for example, to initialise the internal tags). A cyclic trigger will also fire on its own, so this is optional.
  4. If WinCC is on a redundant server pair, replicate the script and tag list to the standby and confirm the licence covers both.

Step 6: Verification and Commissioning

Validate the bridge in three layers: tag level, script level, and process level.

  1. Tag level: Use an I/O field in Graphics Designer bound to ULS_Level_m to confirm the ULS reading updates.
  2. Script level: Open the Global Script diagnostic view (Ctrl + F12 in the VBS editor) and watch HMI_BridgeStatus. The value should remain 0 (OK) under healthy conditions.
  3. Process level: Force DB50.DBD0 on PLC A to 3.00 m (above threshold) using TIA Portal. Within one cycle, Pump_Command_HMI should write 0 to PLC B. Force 1.50 m and the script should write 1 after the dead-band passes.
Forced level (m) Expected Pump_Command_HMI Pass criterion
0.50 1 (start) Within 1 s of trigger fire
2.45 1 (hold, in dead-band) No change from last command
2.55 0 (stop) Within 1 s of trigger fire
Stale tag (unplug PLC A) 0 (safe stop) and HMI_BridgeStatus = 1 Within 1 s of failure detection

Alternative 1: Direct PLC-to-PLC S7 Communication

If the network allows it, replace the HMI bridge with a direct S7 connection. PLC A is the S7 client, PLC B is the S7 server. Two common methods are:

  • S7 PUT/GET — Available on S7-1200 (FW 4.0+ with the "Permit access with PUT/GET" option) and S7-1500. Configure a PUT block in PLC A to copy the level value to a tag in PLC B every cycle. This is the most common cross-PLC pattern and survives HMI outages.
  • Profinet I-Device — Configure PLC A as an I-Device with a Profinet slot for the level value, and PLC B consumes that slot as if it were a remote I/O module. Latency is sub-millisecond.

These methods remove the HMI from the control path, which is the recommended approach whenever the network topology permits.

Alternative 2: OPC UA Method Routing

For S7-1500 controllers, the OPC UA server in the CPU (FW 2.0+) can expose a method that the HMI calls. The HMI script then becomes a single method invocation rather than a periodic tag write, which is cleaner and gives the PLC authority to validate the call.

  1. In the S7-1500 OPC UA server configuration, enable the Methods option and publish a method SetPumpCommand with one input argument of type Boolean.
  2. In the WinCC Unified V20 tag browser, drag the method onto a button.
  3. The button's OnClick event calls the method, passing the calculated pumpCmd as a parameter.

This pattern works for both WinCC Unified and for an external SCADA (Ignition, FactoryTalk) and is documented in the WinCC V8.1 Working with Controls manual.

Alternative 3: WinCC Unified V20 JavaScript

WinCC Unified V20 uses JavaScript instead of VBScript. The equivalent global script lives under Scripts → Global module and is triggered from a scheduled task.

// WinCC Unified V20 — scheduled task body
export async function Bridge_ULS_ToPump() {
    const level = await Tags("ULS_Level_m").Read();
    const threshold = await Tags("ULS_Threshold_m").Read();
    const hysteresis = await Tags("ULS_Hysteresis_m").Read();

    let cmd;
    if (level.value >= threshold.value) {
        cmd = 0;                                 // stop
    } else if (level.value < (threshold.value - hysteresis.value)) {
        cmd = 1;                                 // start
    } else {
        cmd = await Tags("Pump_LastCommand").Read().then(r => r.value);
    }

    await Tags("Pump_Command_HMI").Write(cmd);
    await Tags("Pump_LastCommand").Write(cmd);
    await Tags("HMI_BridgeStatus").Write(level.qualityCode === 0 ? 0 : 1);
}

Unified benefits over V7/V8:

  • Native async/await removes the manual quality-code branching that VBScript requires.
  • Triggers can be 100 ms with deterministic execution.
  • Cross-platform (PC, Panel, Edge) without recompile.

Reference: Process control (RT Unified) - WinCC Unified.

Safety and Reliability Considerations

An HMI-driven control path introduces failure modes that a direct PLC link does not. Address these during design review:

  • HMI server loss. PLC B must contain a watchdog timer reset by the most recent Pump_Command_HMI write. If the HMI is offline for more than the watchdog window, PLC B forces the pump to a defined safe state (typically stop).
  • HMI overload. A 250 ms trigger under heavy graphics load can be deferred. The watchdog above also covers this.
  • Initial state on WinCC startup. The Pump_LastCommand internal tag persists the last command. After a power-cycle, the bridge resumes from the last known state. If the operator requires a manual acknowledgement on restart, the bridge should write 0 on the first trigger tick after startup.
  • Network partition. WinCC will detect the loss of either PLC connection through the S7 channel quality code. The script's quality-code branch forces the safe state.
  • Cyber security. Allow only authenticated S7 connections and disable the HMI's external WebUX (if not required) to reduce the attack surface. A cross-PLC bridge inside the HMI is a tempting pivot point for an attacker.

Troubleshooting Matrix

Symptom Likely cause Resolution
Pump never responds to level change Global Script Runtime not enabled Computer → Properties → Startup → tick Global Script Runtime, restart runtime
Pump chatters at threshold No hysteresis in script Set ULS_Hysteresis_m to 5–10 % of threshold
Script log shows Type mismatch Internal tag data type mismatch Re-create ULS_Threshold_m as Float 32-bit IEEE 754, not Integer
Quality code 6 on ULS_Level_m PLC A connection lost Check channel diagnostics, ping PLC A, verify TSAP and rack/slot
Pump_Command_HMI writes flicker 0/1/0/1 Trigger period shorter than S7 write time Lengthen trigger to 1 s, or move to a single batched tag list write
HMI_BridgeStatus stuck at 1 after recovery Status tag not cleared on success branch Verify the status = 0 write executes; check that Read quality code on each tag is 0
Pump trips on every WinCC restart Pump_LastCommand initialised to 1 Change initial value to 0, or add a startup handshake in PLC B

FAQ

Can I route any tag type through this pattern, or only booleans?

Any tag type works. The example uses a REAL (level) and a BOOL (command), but the same HMIRuntime API handles INT, WORD, DWORD, and STRING. For strings larger than 256 bytes, use the S7 channel's raw pointer or move the data via a sequenced PUT/GET rather than a global script.

What is the minimum reliable trigger period for a WinCC V7.x Global Script?

500 ms is the practical floor for a single-action script on a typical IPC. Values below 250 ms can collide with the WinCC graphics scheduler and produce non-deterministic firing. For sub-second response, switch to WinCC Unified V20, where 100 ms scheduled tasks are supported.

Will the bridge still work if WinCC Runtime is restarted while the plant is running?

The HMI loses contact with both PLCs during the restart. PLC B should contain a watchdog that trips the pump to a safe state if no command refresh arrives within 3–5 seconds. When WinCC returns, the first trigger tick re-establishes the bridge and Pump_Command_HMI resumes from Pump_LastCommand (or from a forced 0 if you add a startup reset).

Why is the quality code from HMIRuntime.Tags(...).Read important?

A non-zero quality code means the HMI's last cached value for that tag is stale (PLC unreachable, address invalid, or driver not licensed). Acting on a stale value is the most common cause of phantom control commands. The script in this article treats any non-zero quality as a fault and forces the pump off.

Is there a way to do this without writing a VBScript at all?

Yes, if both PLCs support OPC UA. Enable the OPC UA server on PLC A and PLC B, configure the HMI as an OPC UA client, and use a tag connection with a derived/internal tag to do the mapping. For level-to-command logic with hysteresis, however, the script remains the simplest implementation, because the decision must live somewhere in the runtime.

Back to blog