WinCC OA Widget Architecture

Data Flow Overview

The data flow architecture is based on a 3-layer model:

┌───────────────┐      ┌──────────────────┐     ┌─────────────┐
│  WinCC OA     │────▶│  Context         │────▶│  Widget     │
│  Backend      │      │  (WebComponent)  │     │  (WebComp)  │
│               │      │                  │     │             │
│ - Datapoints  │      │ - Subscribes DP  │     │ - Receives  │
│ - Archives    │      │ - Transforms     │     │   attributes│
│ - Alarms      │      │ - Filters        │     │ - Renders   │
└───────────────┘      └──────────────────┘     └─────────────┘
  1. Widget (UI Element): A "dumb" WebComponent that only receives data via attributes/properties, displays data, and emits events. It does not know where data comes from.

  2. Context Components (Middleware): WebComponents that wrap the widget as a parent element. They handle all backend communication, data transformation, and event handling.

  3. Widget Instance (JSON Configuration): The binding between widget and context stored as JSON, defining which data sources feed which widget attributes.

This architecture ensures widgets are fully decoupled from data sources - the context layer handles all backend communication while widgets only need to know which attributes they expect.

Dashboard Widgets

UI Widgets in the WinCC OA dashboard are simple WebComponents - they follow standard WebComponent rules and practices, are built using standard HTML, CSS, and JavaScript or TypeScript and use attributes and events to retrieve and send information. The architecture of a widget is designed to be modular and reusable. A widget should be only used to display data and react to user events. Frontend logic should be limited and data retrieval should be avoided in the widget itself. A widget does not need to know where the data is coming from nor does it need to know of any restrictions or connections introduced by the data provider which could be a WinCC OA backend.

Context Component

To retrieve data from the WinCC OA backend another layer is implemented on the app side already. This layer is called "context". The context can be configured to e.g. retrieve a live or historic value, a pending alarm or a setting (e.g. the defined unit, the format or a name) of a datapoint. The widget itself does not need to know about the chosen datapoint - it will only get those attributes defined in the widget's JSON schema. There are also contexts that transform inputs in a way that the use within the UI element can be streamlined. E.g. there is a translate context, that can be configured with a multi-lang text (an object that holds a corresponding string for each configured language) and the context will forward only the text in the current frontend language. By doing this, the UI element does not need to know anything about the language or the translation. It just needs to know that it has a text input and that it should display this text. The context will take care of the rest. Technically the UI Element is a HTML child of the context which is also a WebComponent.

There are also contexts that react to events that are triggered within the UI element. E.g. a dpset context can be used, to set the value of a datapoint to a value that is given by the UI element's event. Another context can be used to navigate to a specified URL when the UI element emits an event.

There are structural contexts such as a group or an array context. Those are used to build up complex objects of data that can be used in the UI element.

Widget instance

When using a widget in a dashboard, the whole HTML markup will be generated automatically based on the settings that are given to that dashboard. Those settings are represented as a JSON string and can be referred as a widget instance. The settings are generated on the settings page by a predefined component using JSONForms.

Within the serialized JSON string, a context is always represented in the same way, as a JSON object with the following structure:

{
  "context": "<context-type>",
  "config": {
    // context specific configuration
  }
}

In most cases static values given by the user are forwarded to the UI element. In such case a static context is utilized:

{
  "context": "static",
  "config": {
    "value": "<value>"
  }
}

The configuration of the array context is the only the one that differs slightly, because its config is also an array.

{
  "context": "array",
  "config": [
    // list of group contexts
  ]
}

To create complex objects in which each property is retrieved by a different context a group context is needed to combine those contexts. The config of the group context is a JSON object with the following structure:

{
  "context": "group",
  "config": {
    "property1": {
      "context": "<context-type>",
      "config": {
        // context specific configuration
      }
    },
    "property2": {
      "context": "<context-type>",
      "config": {
        // context specific configuration
      }
    }
  }
}

Generating a widget instance using JSON forms

The widget instance is generated using JSONForms, which in turn is again generated by providing JSON files describing necessary attributes, their types and their layout within the settings page. See oa-widget-schemas.md for more information about JSONForms and how to create a JSON schema.

Each Control defined in the JSON UI schema (e.g. "type": "FontSizeSelectControl"), will emit an object with a certain type of context configuration. In most cases it is a static context and the value provided by the user is directly forwarded to the UI element. In more complex examples like the "type": "DataPointControl" the generated setting object consists of more information like in the example below. In this example the UI element will receive all attributes given in definedConfigs with the corresponding value of the datapoint given in dpName. The context will take care of querying this information, the UI element will just receive the final values.

Example widget instance

{
  "id": "4d3edd59-0c7c-464d-b5a9-71908cb638dc",
  "version": 2,
  "x": 12,
  "y": 0,
  "rows": 8,
  "cols": 8,
  "minCols": 6,
  "minRows": 6,
  "name": "WUI_Widget_Trend.Label",
  "settings": {
    "config": {
      "context": "group",
      "config": {
        "series": {
          "context": "array",
          "config": [
            {
              "context": "group",
              "config": {
                "datapoint": {
                  "context": "data-point",
                  "config": {
                    "definedConfigs": ["datapoint", "value", "name", "unit", "format", "color", "min", "max", "alertColor"],
                    "compress": true,
                    "dpName": "System1:ExampleDP_Arg1.",
                    "fetchMethod": "historic",
                    "historic": { "sTimeRange": "1h" },
                    "customName": false
                  }
                },
                "lineStyle": "solid"
              }
            }
          ]
        },
        "showLegend": true,
        "showRangePicker": true,
        "legendOrientation": "horizontal",
        "legendVerticalPosition": "top",
        "legendHorizontalPosition": "center",
        "showXAxisGrid": false,
        "showYAxisGrid": true,
        "yAxisColor": "",
        "zoom": 1
      }
    },
    "jsonFileName": "StandardLibrary/Charts/linechart.widget"
  },
  "component": {
    "scripts": ["trend"],
    "tagname": "wui-widget-trend"
  }
}

Context Types Reference

The following context types are available for data binding in widget instances and standalone pages:

Context Purpose Config
static Forward a fixed value to the widget { "value": "<value>" }
data-point Connect to a WinCC OA datapoint (live or historic) { "dpName": "...", "definedConfigs": [...] }
group Combine multiple contexts into a single object { "prop1": { "context": "...", "config": {...} }, ... }
array Create an array from multiple configs [ { "context": "...", "config": {...} }, ... ]
translate Translate a multi-lang text to the current language { "en_US.utf8": "English", "de_AT.utf8": "Deutsch" }
dpset Write a value to a datapoint on event { "dpName": "...", "value": 75 }

static

Forwards a user-provided value directly to the widget attribute.

{
  "context": "static",
  "config": { "value": "hello" }
}

data-point

Connects to a WinCC OA datapoint. Supports live values, historic data, and event-based writing.

Available definedConfigs: value, min, max, unit, format, alertColor, color, name

{
  "context": "data-point",
  "config": {
    "dpName": "System1:ExampleDP_Arg1.",
    "definedConfigs": ["value", "name", "unit", "format", "color", "min", "max", "alertColor"],
    "fetchMethod": "historic",
    "historic": { "sTimeRange": "1h", "compress": true, "fields": ["values", "timestamps"] },
    "dpSet": { "event": "change", "validate": true }
  }
}

group

Combines multiple contexts into a single object. Each property of the config is resolved by its own context.

{
  "context": "group",
  "config": {
    "label": { "context": "translate", "config": { "en_US.utf8": "Tank 1" } },
    "value": { "context": "data-point", "config": { "dpName": "System1:Tank1.", "definedConfigs": ["value"] } }
  }
}

array

Creates an array from a list of contexts (typically group contexts).

{
  "context": "array",
  "config": [
    { "context": "group", "config": { "value": { "context": "data-point", "config": { "dpName": "System1:Tank1.", "definedConfigs": ["value"] } } } },
    { "context": "group", "config": { "value": { "context": "data-point", "config": { "dpName": "System1:Tank2.", "definedConfigs": ["value"] } } } }
  ]
}

translate

Resolves a multi-language object to the current frontend language.

{
  "context": "translate",
  "config": { "en_US.utf8": "Temperature", "de_AT.utf8": "Temperatur" }
}

dpset

Sets a datapoint value when a UI event occurs (e.g., button click).

{
  "context": "dpset",
  "config": { "dpName": "System1:MyDatapoint.", "value": 75 }
}