Resolving WinCC Unified Trend Control Dynamic Add Failures via Script
Programmatically adding trend curves to a WinCC Unified Trend Control at runtime using a button click event frequently fails in the same way across TIA Portal V17, V18, V19, and V20 builds: the trend count increments, but the new trend is added with no tag binding and no legend label. Operators see an empty row in the trend viewer that does not log or render data, and any configuration performed at runtime is discarded the moment the operator navigates away from the screen.
This article documents the three independent root causes, the Siemens-recommended pre-configure pattern from the TIA Portal V20 faceplate documentation, and four field-proven JavaScript patterns that bind tags to a trend curve reliably at runtime on MTP Unified Comfort Panels and Unified PC Runtime.
SetTimeout shown in the source code is not a fix; it is a symptom that the script is racing the asynchronous trend object construction. A 50–200 ms delay is the correct magnitude, and even that becomes unnecessary once the trend is pre-configured in TIA Portal.1. Problem Description
In a typical WinCC Unified HMI project, an engineer wants to expose operator-driven trend selection through a faceplate. The user enters a tag name in an IO field on the faceplate, presses a button, and expects a new trend curve to appear in a trend control on the host screen bound to that tag. The implementation typically follows this pattern:
// Inside the faceplate button click handler
let plctag = Tags("UDT_HMI.Tag").Read();
let hmitag = Faceplate.Properties.UDT_HMI.Tag + ".PV";
let parameters = { plctag: plctag, hmitag: hmitag };
Faceplate.RaiseEvent("MyCustomEventName", parameters);
// On the host screen, subscribed to the custom event
export function _20_LIC0_HMI_OnMyCustomEventName(item, hmitag, plctag) {
let count = Screen.Items("ctlTrendView").TrendAreas.Item(0).Trends.Count;
Screen.Items("ctlTrendView").TrendAreas[0].Trends.Add(count);
HMIRuntime.Timers.SetTimeout(() => {
Screen.Items("ctlTrendView").TrendAreas[0].Trends[count].DataSourceY.Source = hmitag;
Screen.Items("ctlTrendView").TrendAreas[0].Trends[count].DisplayName = plctag;
}, 5000);
}
Three failure modes are reproducible in the field:
-
Empty trend added:
Trends.Countincrements, butDataSourceY.SourceandDisplayNameremain undefined. - Trend added with name but no data: The legend shows the tag name, but the curve renders no data points and no logging entries are created.
- Configuration lost on screen change: When the operator navigates away from the screen and returns, every runtime-added trend and its tag binding is gone.
2. Root Cause Analysis
Three independent root causes combine to produce the failure. Addressing only one of them yields the "sometimes works, sometimes not" behavior reported in the source thread.
2.1 Asynchronous Trend Object Construction
The Trends.Add(index) method initiates trend creation on the runtime's rendering pipeline. The JavaScript wrapper immediately returns a trend object reference, but the internal slot for the data source, the legend entry, and the time range are initialized asynchronously. A direct property assignment on the next line of script does not guarantee the runtime has finished construction. The 5-second SetTimeout in the source code is an attempt to outrun this race condition, and the fact that it still sometimes fails confirms the timing model is wrong.
Empirically, 50–200 ms is the correct order of magnitude for the construction to complete on an MTP1900 Comfort Panel. The 5-second value is roughly 25–100× longer than required and indicates the engineer observed the property assignment failing and increased the timeout until it appeared to work, without understanding the underlying cause.
2.2 DataSourceY.Source Type Mismatch
The DataSourceY.Source property expects an HMI tag reference object, not a raw string. When a script writes Trends[count].DataSourceY.Source = hmitag where hmitag is a string, the assignment can silently no-op depending on the TIA Portal version. In V17, the runtime accepted the string and coerced it; in V18 the coercion became stricter; in V19 and V20 the property setter validates the type and rejects strings without an error message.
The official TIA Portal V20 documentation for configuring a trend control with logging tags in a faceplate demonstrates that logging tags must be assigned through the configuration UI; runtime tag binding requires the fully qualified HMI tag path including the connection name, not just the tag name.
2.3 Trend Configuration Is Volatile by Default
Trend control configuration is screen-local. When the operator navigates away from the screen and returns, all runtime-added trends and their tag bindings are discarded. The default WinCC Unified behavior recreates the trend control from the engineering configuration, which contains only the pre-configured trends. RT Persistency must be enabled in the HMI device configuration to preserve runtime modifications across screen changes.
3. Prerequisites
- TIA Portal V18, V19, or V20 with WinCC Unified Comfort/Professional panel or Unified PC Runtime installed.
- WinCC Unified Runtime V18 or higher on the target device (MTP1500, MTP1900, MTP2200, TP1500, TP2200, or Unified PC RT V18+).
- A configured trend control on the host screen with at least one trend area and at least one pre-configured trend curve.
- A faceplate instance exposing a
UDT_HMI.Tagproperty of typeStringorWString. - Engineering access to the HMI device configuration to enable RT Persistency on the control configurations.
- For logging tag use: a configured data log with at least one logging tag accessible to the trend control.
4. The WinCC Unified Trend Object Model
Understanding the runtime object hierarchy is essential for writing reliable trend configuration scripts. The object model in WinCC Unified V18+ differs materially from the WinCC Comfort/Advanced V15/V16 model.
| Object Path | Type | Description | V18+ |
|---|---|---|---|
Screen.Items("ctlTrendView") |
HMIControl |
Trend control instance on the active screen | Yes |
TrendAreas |
Collection<TrendArea> |
Container of all trend areas in the control | Yes |
TrendAreas[0] |
TrendArea |
First trend area; zero-indexed | Yes |
Trends |
Collection<Trend> |
Container of trend curves within the area | Yes |
Trends.Add(index) |
Method: Integer |
Appends a new trend and returns its index | Yes |
Trends.Count |
Property: Integer (read-only) |
Current number of trend curves | Yes |
Trends[index].DataSourceY.Source |
Property: HmiTagRef / String |
Tag binding for Y-axis data; requires fully qualified path in V19+ | Yes |
Trends[index].DisplayName |
Property: String |
Label rendered in the legend | Yes |
Trends[index].Visible |
Property: Boolean |
Show or hide the trend in the viewer | Yes (V18+) |
SelectedTrend |
Property: Trend (read-only) |
Reference to the operator-selected trend; null if no selection | Yes |
SelectedIndex |
Property: Integer (read-only) |
Index of the selected trend; -1 if no selection | Yes (V19+) |
5. Approach 1: Pre-Create Trends with PLC Tag Visibility (Siemens Recommended)
The Siemens-recommended pattern from the TIA Portal V20 faceplate trend documentation is to pre-configure the trends in the engineering tool and control their visibility at runtime through a PLC tag. The runtime API is then used only to toggle the Visible property and update the DataSourceY.Source on an already-constructed trend, not to add new trend objects.
5.1 Engineering Configuration
- Open the trend control in the screen editor.
- In the Inspector window, under Properties > Trends, add the maximum number of operator-selectable trends the screen should ever show. For most operator-driven use cases, 8–16 pre-configured trends is sufficient.
- For each pre-configured trend, set the data source to a placeholder HMI tag of the correct data type. The placeholder is replaced at runtime via the script.
- Add a Boolean HMI tag for each pre-configured trend (e.g.,
HMI\_Trend\_Visibility\_0throughHMI\_Trend\_Visibility\_N). Bind each trend'sVisibleproperty to the corresponding tag. - Compile and download the project to the panel.
5.2 Runtime Script Pattern
// Host screen: subscribe to the faceplate custom event
export function Screen_OnMyCustomEventName(item, hmitag, plctag) {
// Find the first hidden trend slot
let trends = Screen.Items("ctlTrendView").TrendAreas[0].Trends;
let slotIndex = -1;
for (let i = 0; i < trends.Count; i++) {
if (!trends[i].Visible) {
slotIndex = i;
break;
}
}
if (slotIndex === -1) {
HMIRuntime.Trace("TrendControl: no free slot");
return;
}
// Bind the tag and make the trend visible.
// The trend object is already constructed because it was pre-configured,
// so the property assignment is synchronous and reliable.
trends[slotIndex].DataSourceY.Source = hmitag;
trends[slotIndex].DisplayName = plctag;
trends[slotIndex].Visible = true;
HMIRuntime.Trace("TrendControl: bound slot " + slotIndex + " to " + hmitag);
}
This pattern eliminates the asynchronous construction race because the trend object exists from the moment the screen loads. The Visible toggle is the only property that changes the operator experience, and it is fully synchronous.
6. Approach 2: SelectedTrend API for Operator-Click Binding
When the operator manually selects a trend curve in the viewer (by clicking on its legend entry or the curve itself), the trend control exposes a SelectedTrend property. A script can then update that trend's tag binding without needing to add a new trend. This is the simplest pattern and is the one the source thread observed to "sometimes work."
6.1 Why It Sometimes Fails
The SelectedTrend property returns null if the operator has not selected a trend, and the script's property assignment silently no-ops in that case. The "sometimes works" behavior occurs when the operator clicks the trend curve before pressing the bind button. To make this reliable, gate the assignment on a non-null SelectedTrend and provide user feedback when no trend is selected.
6.2 Reliable SelectedTrend Pattern
// Button click handler: rebind the currently selected trend
export function Button_BindSelectedTrend_OnClick(item) {
let trend = Screen.Items("ctlTrendView").TrendAreas[0].SelectedTrend;
if (trend === null || trend === undefined) {
HMIRuntime.Trace("TrendControl: no trend selected");
// Optional: write to an HMI tag the screen uses to show a status message
Tags("HMI_BindStatus").Write("Select a trend in the viewer first");
return;
}
// Read the requested tag from the faceplate property bag
let hmitag = Faceplate.Properties.UDT_HMI.Tag + ".PV";
let plctag = Tags("UDT_HMI.Tag").Read();
trend.DataSourceY.Source = hmitag;
trend.DisplayName = plctag;
HMIRuntime.Trace("TrendControl: rebound selected trend to " + hmitag);
}
SelectedTrend reference is invalidated when the operator changes the selection or when the trend control re-renders. Cache the index, not the reference, if the script needs to operate on the same trend across multiple events.7. Approach 3: Dynamic Add with Verification Loop
If the engineering constraint requires adding a new trend curve at runtime (for example, the maximum number of trends is genuinely unbounded), the Trends.Add() call can be made to work, but it requires polling for construction completion rather than a fixed SetTimeout. The 5-second timeout in the source code is replaced with a verification loop that polls the trend's DataSourceY property.
// Host screen: dynamic add with construction verification
export function Screen_OnMyCustomEventName(item, hmitag, plctag) {
let area = Screen.Items("ctlTrendView").TrendAreas[0];
let count = area.Trends.Count;
area.Trends.Add(count);
// Poll for construction completion; max 20 attempts at 50ms = 1s total
let attempts = 0;
let poll = HMIRuntime.Timers.SetInterval(() => {
attempts++;
let trend = area.Trends[count];
if (trend && trend.DataSourceY) {
// Construction is complete; bind and stop polling
trend.DataSourceY.Source = hmitag;
trend.DisplayName = plctag;
HMIRuntime.Timers.ClearInterval(poll);
HMIRuntime.Trace("TrendControl: bound trend " + count + " after " + attempts + " polls");
} else if (attempts >= 20) {
HMIRuntime.Timers.ClearInterval(poll);
HMIRuntime.Trace("TrendControl: construction timeout for trend " + count);
}
}, 50);
}
This pattern is less reliable than Approach 1 and is the most fragile to runtime version differences. Reserve it for the case where pre-creating trends is genuinely not viable.
8. Approach 4: Persistent Runtime Configuration
All three approaches above still suffer from the volatility problem: when the operator navigates away and returns, the runtime-added bindings are gone. To preserve them, enable RT Persistency on the control configurations.
8.1 Enabling RT Persistency for Trend Configurations
- In the TIA Portal project tree, select the HMI device (for example,
HMI_1 [MTP1900]). - Open the device configuration and navigate to Runtime settings > Persistency.
- Enable Activate RT Persistency for control configurations.
- Set the storage location to Local file system (for panels) or to the configured path on the Unified PC Runtime.
- Configure the persistency scope to include the screen containing the trend control.
With RT Persistency enabled, the runtime saves the trend control's state (visible trends, tag bindings, time range, zoom level) to the local file system at the configured interval. On screen reload, the runtime restores the saved state instead of recreating the control from the engineering configuration.
9. Faceplate-to-Screen Event Wiring
The source code raises a custom event from inside the faceplate and subscribes on the host screen. The complete wiring is shown below for reference.
9.1 Faceplate Interface Definition
In the faceplate type, define the interface property and the custom event:
- Property:
UDT_HMI.Tag, typeString, visibility Public - Event:
MyCustomEventName, payload{plctag:String, hmitag:String}
9.2 Faceplate Button Click Script
// Faceplate: button "Add to Trend" click handler
export function Button_AddTrend_OnClick(item) {
let plctag = Tags("UDT_HMI.Tag").Read();
let hmitag = Faceplate.Properties.UDT_HMI.Tag + ".PV";
HMIRuntime.Trace("Faceplate: plctag=" + plctag + " hmitag=" + hmitag);
if (!hmitag || hmitag === ".PV") {
HMIRuntime.Trace("Faceplate: invalid tag entered");
return;
}
let parameters = { plctag: plctag, hmitag: hmitag };
Faceplate.RaiseEvent("MyCustomEventName", parameters);
}
9.3 Screen-Level Event Subscriber
On the host screen, the faceplate instance _20_LIC0_HMI exposes a generated event handler _20_LIC0_HMI_OnMyCustomEventName. The handler receives the parameter object as its argument.
// Screen: faceplate event subscriber (using Approach 1)
export function _20_LIC0_HMI_OnMyCustomEventName(item, parameters) {
let hmitag = parameters.hmitag;
let plctag = parameters.plctag;
let area = Screen.Items("ctlTrendView").TrendAreas[0];
let trends = area.Trends;
// Find the first hidden trend slot
for (let i = 0; i < trends.Count; i++) {
if (!trends[i].Visible) {
trends[i].DataSourceY.Source = hmitag;
trends[i].DisplayName = plctag;
trends[i].Visible = true;
HMIRuntime.Trace("Trend: bound slot " + i);
return;
}
}
HMIRuntime.Trace("Trend: no free slot");
}
10. Step-by-Step Implementation Guide
-
Pre-configure the trend control. In TIA Portal, add the trend control to the host screen. In Properties > Trends, add 8 trend curves, each bound to a placeholder HMI tag. Bind each trend's
Visibleproperty to an HMI Boolean tag (HMI_Trend_Visible_0throughHMI_Trend_Visible_7). Set all visibility tags tofalsein the HMI tags table. - Enable RT Persistency. In the HMI device configuration, enable RT Persistency for control configurations. Set the storage path and the persistency interval (default 30 s is acceptable for trend configurations).
-
Create the faceplate interface. Add the
UDT_HMI.Tagproperty and theMyCustomEventNameevent to the faceplate type. -
Write the faceplate button script. Use the script from Section 9.2. The script reads the entered tag, builds the HMI tag reference (with the
.PVsuffix for UDT members), validates it is non-empty, and raises the custom event with the parameter object. - Write the screen event subscriber. Use the script from Section 9.3. The subscriber finds the first hidden trend slot, binds the tag, sets the display name, and toggles the visibility tag.
- Compile and download. Compile the HMI project and download it to the panel. Verify the project compiles without warnings related to the trend control or the faceplate interface.
- Run the HMI Runtime in simulation mode first. Use the TIA Portal Start HMI Runtime option to launch the WinCC Unified Runtime on the engineering station. Enter a tag name in the faceplate IO field, press the button, and verify a new trend appears in the viewer with the correct data.
- Deploy to the panel. Once the simulation behavior is verified, download the project to the MTP panel and repeat the operator flow on the physical device.
- Verify persistency. Add several trends, navigate to another screen, and return. Verify the trends are still visible with the correct tag bindings. If they are not, re-check the RT Persistency configuration.
11. Verification Procedures
After deploying the script, run the following verification steps on the target device:
| Step | Action | Expected Result | Failure Indicates |
|---|---|---|---|
| V1 | Enter a valid tag name in the faceplate IO field, press the button. | A new trend curve appears in the trend viewer with the entered tag's data. | Event wiring broken, or trend slot search failed. |
| V2 | Enter a second valid tag, press the button. | A second trend curve appears, the first remains visible. | Slot allocation logic is reusing the same index. |
| V3 | Press the button with an empty IO field. | No trend is added; a trace message or status tag indicates invalid input. | Input validation missing or the early return is not firing. |
| V4 | Navigate away from the screen and return. | The added trends are still visible with the correct tag bindings. | RT Persistency not enabled or scope misconfigured. |
| V5 | Reboot the panel, log in, and navigate to the trend screen. | The trends added before the reboot are still visible. | RT Persistency storage path not writable, or persistency not flushing before shutdown. |
| V6 | Check the trend log on the HMI device. | Logging entries exist for each bound tag with the expected timestamp and value. | Data source is bound to the wrong tag, or the logging tag configuration is missing. |
| V7 | Check the runtime trace log. | Trace messages show the slot index, the bound tag, and the poll count (if using Approach 3). | Script errors are being swallowed silently; add explicit Trace calls at each branch. |
12. Troubleshooting Matrix
| Symptom | Likely Root Cause | Fix |
|---|---|---|
| Trend added but no name and no data | Property assignment lost in async construction race | Switch to Approach 1 (pre-create with visibility) or use verification loop in Approach 3 |
| Trend added with name but no data points |
DataSourceY.Source is a raw string, not a tag reference |
Use the fully qualified HMI tag path with connection name; verify in the trace log |
| Trend added and bound, but no logging entries | Tag is not a logging tag, or the data log is not enabled | Configure a data log with the tag as a logging tag; enable the log in the runtime |
| Configuration lost on screen change | RT Persistency not enabled | Enable RT Persistency in device configuration; verify storage path is writable |
| Configuration lost on panel reboot | RT Persistency storage path is on a volatile mount, or flush interval too long | Reduce the persistency interval to 5–10 s; verify the storage path is on the local file system, not a network share |
| Script error in trace: "Cannot read property 'DataSourceY' of undefined" | Trend at the given index does not exist; the Add() call did not complete |
Add a construction verification loop before accessing properties |
| Only one trend is ever added even with multiple button presses | Slot search finds the same index because visibility toggle is not propagating | Verify the HMI visibility tag is bound to the trend's Visible property in the engineering configuration |
| Script works in simulation but fails on the panel | Runtime version mismatch between engineering and target | Check the panel's runtime version under Control Panel > System > About; match the engineering version |
13. Performance and Sizing Notes
The number of pre-configured trend curves directly affects the screen's render time and the panel's memory consumption. Use the following rough sizing rules for MTP Unified Comfort Panels:
| Panel | RAM Available for HMI | Recommended Max Pre-Configured Trends per Control | Max Trend Controls per Screen |
|---|---|---|---|
| MTP1500 | ~512 MB | 8 | 1 |
| MTP1900 | ~1 GB | 16 | 2 |
| MTP2200 | ~2 GB | 24 | 3 |
| Unified PC RT V18+ | System-dependent | 32+ | 4+ |
Each pre-configured trend reserves memory for the trend buffer and the legend entry, even when Visible is false. For panels in the lower RAM tier, keep the pre-configured count conservative and rely on the dynamic Add() pattern only for the case where the operator's maximum trend count is genuinely unbounded.
14. Best Practices and Field Notes
-
Always pre-configure the maximum number of trends the operator will ever need. The Siemens-recommended pattern uses pre-configured trends with visibility tags. Reserve the dynamic
Add()pattern for cases where pre-configuration is not viable. -
Never assign a raw string to
DataSourceY.Sourcein V19+. Build the fully qualified HMI tag path including the connection name when binding from a script. - Always enable RT Persistency for control configurations when the operator's trend setup is expected to survive screen changes or reboots.
- Add trace messages at every branch of the slot-search and binding logic. Silent failures are the dominant debugging cost in WinCC Unified scripting; trace messages are the only reliable diagnostic on a panel without a debugger.
- Test on the target device, not just in simulation. The WinCC Unified simulation runs on the engineering PC's full .NET runtime; the panel runs a constrained RT runtime. Behavior can differ, especially for asynchronous APIs and persistency.
-
Use the
SelectedTrendAPI for the operator-driven rebind flow rather than the dynamicAdd()flow whenever the use case is "change the tag bound to an existing visible trend." - Validate the faceplate IO field input before raising the custom event. An empty or malformed tag reference produces a script error in the subscriber that is difficult to trace back to the faceplate input.
15. Reference Documentation
The following official Siemens documentation is the authoritative source for the trend control runtime API and the faceplate trend configuration pattern. The V20 faceplate documentation is the source of the pre-configure pattern used in Approach 1.
Why does Trends.Add() add the trend but leave the data source empty?
The Add() method returns a trend reference synchronously, but the internal data source slot is constructed asynchronously by the rendering pipeline. A direct property assignment on the next script line races the construction. Use the pre-configured trend pattern with visibility tags (Approach 1) or poll for construction completion (Approach 3) to eliminate the race.
How do I bind a tag to a trend that the operator has selected in the viewer?
Use the trend control's SelectedTrend property. Read it after the operator clicks the trend, gate the script on a non-null value, then assign SelectedTrend.DataSourceY.Source and SelectedTrend.DisplayName. The assignment is synchronous because the selected trend is already constructed.
How do I keep the operator's trend configuration across screen changes and reboots?
Enable RT Persistency for control configurations in the HMI device configuration under Runtime settings > Persistency. Set the storage path to the local file system and the persistency interval to 5–30 seconds. The runtime then saves the trend control's state and restores it on the next screen load.
What is the maximum number of pre-configured trends a WinCC Unified panel can hold?
The limit is determined by panel RAM and by the screen's render time budget. For MTP1500 keep it under 8 trends per control; for MTP1900 under 16; for MTP2200 under 24. Each pre-configured trend reserves memory for the trend buffer and legend even when Visible is false.
Why does the script work in the TIA Portal simulation but fail on the physical panel?
The WinCC Unified simulation runs on the engineering PC's full .NET runtime; the panel runs a constrained RT runtime. Differences in the runtime version, the rendering pipeline, and the persistency storage path can cause the script to fail on the panel. Always match the engineering version to the panel's installed runtime version, and test the final deployment on the physical device.