> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Siemens WinCC Unified (GraphQL server)

> Client-mode REST API connector for the Siemens WinCC Unified Runtime GraphQL server: log in as a WinCC Unified user, browse tags, read and write live tag values, read logged tag values, list active and logged alarms, and acknowledge, reset, shelve or disable alarms from MQTT

Technical Preview

## Overview

WinCC Unified is the Siemens SCADA / HMI system in TIA Portal. From V19 on, Unified Runtime on a PC includes a **GraphQL server** for reading and writing runtime data: tags, logged (historical) tag values and alarms. Siemens documents it in the online help **WinCC Unified GraphQL (RT Unified)**.

The **WinccUnifiedGraphql** connector sends GraphQL queries and mutations over HTTPS. Every event is a `POST /graphql/` with a JSON body `{"query": "...", "variables": {...}}`. The topic picks the preset and the payload carries the GraphQL document, so you control exactly which fields come back. Typical uses: mirror HMI tags onto MQTT, write setpoints from MQTT, pull tag history into a historian or analytics pipeline, and acknowledge alarms from another system. Each event publishes the server's reply on `<topic>/response`.

| Event | Topic | GraphQL operation | Notes |
| - | - | - | - |
| Login | `historian/siemens-wincc-unified/session/create` | `mutation login` | UMC user configured for Runtime -> data.login.token (Bearer) + expires; error 101 wrong credentials, 102 UMC error |
| ExtendSession | `historian/siemens-wincc-unified/session/update` | `mutation extendSession` | Renew the current session (new expires) |
| Logout | `historian/siemens-wincc-unified/session/delete` | `mutation logout` | End this session (allSessions true = every session of the user) |
| GetSession | `historian/siemens-wincc-unified/session/get` | `query session` | Current session and user (token check) |
| BrowseTags | `historian/siemens-wincc-unified/tag/browse` | `query browse` | Find tags, alarms, logging tags by name filter (wildcards) and object type |
| ReadTagValues | `historian/siemens-wincc-unified/tag-value/get` | `query tagValues` | Current values (value, timestamp, quality); directRead true reads from the PLC instead of the cache |
| WriteTagValues | `historian/siemens-wincc-unified/tag-value/update` | `mutation writeTagValues` | Write values \{name, value\[, timestamp, quality]}; error 2 unknown tag, 201 cannot convert value |
| ReadLoggedTagValues | `historian/siemens-wincc-unified/logged-tag-value/list` | `query loggedTagValues` | Historical values of logging tags (Tag:LoggingTag, or the tag when it has one logging tag); startTime or endTime required, maxNumberOfValues if only one is set |
| ListActiveAlarms | `historian/siemens-wincc-unified/active-alarm/list` | `query activeAlarms` | Active alarms; filterString = WHERE part of ChromQueryLanguage (error 301 syntax) |
| ListLoggedAlarms | `historian/siemens-wincc-unified/logged-alarm/list` | `query loggedAlarms` | Alarm history from the alarm log |
| AcknowledgeAlarms | `historian/siemens-wincc-unified/alarm/acknowledge` | `mutation acknowledgeAlarms` | Acknowledge alarms \{name\[, instanceID]}; instanceID 0 = every instance; 305 not acknowledgeable in this state |
| ResetAlarms | `historian/siemens-wincc-unified/alarm/reset` | `mutation resetAlarms` | Reset alarms that need a reset |
| ShelveAlarms | `historian/siemens-wincc-unified/alarm/shelve` | `mutation shelveAlarms` | Shelve configured alarms (optional shelveTimeout) |
| UnshelveAlarms | `historian/siemens-wincc-unified/alarm/unshelve` | `mutation unshelveAlarms` | Revert shelve |
| DisableAlarms | `historian/siemens-wincc-unified/alarm/disable` | `mutation disableAlarms` | Disable configured alarms (no new instances) |
| EnableAlarms | `historian/siemens-wincc-unified/alarm/enable` | `mutation enableAlarms` | Enable configured alarms again |
| GraphqlRequest | `historian/siemens-wincc-unified/graphql/query` | `any query / mutation` | Any query or mutation of the schema (payload decides); subscriptions are not possible over REST\_API |

## Prerequisites

1. **WinCC Unified Runtime on a PC (V19 or later)** with a project running and the GraphQL server available. Siemens documents it online for V20 and V21. Unified Comfort Panels are not covered by the Siemens GraphQL help.
2. The Runtime **IIS web server** reachable from the broker host on HTTPS 443. The GraphQL server is published at `https://<runtime-host>/graphql/`. The GraphQL service listens on port 4000 on the runtime PC, but Siemens does not support direct access to it. Always go through IIS.
3. The broker must **trust the Runtime web server certificate**, either the self-signed certificate or a CA created with WinCC Unified Certificate Manager. The host name or IP in `BASE_ADDRESS` must be in that certificate. Use IPv4 when you connect by host name.
4. A **UMC user configured for Runtime**. Read rights are needed for queries, write rights for `writeTagValues` and the alarm mutations. Objects the user cannot read are left out of responses, and a write without permission aborts the operation.

## Authentication

1. Log in: publish the `login` mutation to `historian/siemens-wincc-unified/session/create` (example below). The response has `data.login.token` and `data.login.expires`. A wrong user or password returns `data.login.error.code` `101` and no token. `102` is a UMC error.
2. Send `"token": "<data.login.token>"` with every other event. The connector sends it as `Authorization: Bearer <token>`.
3. A session stays open while there is activity. `ExtendSession` (`session/update`) renews it, and `Logout` (`session/delete`) ends it. `allSessions: true` ends every session of the user. Changing the user's password and logging out with `allSessions: true` also closes them.
4. Without a valid token, the server answers with an `errors` array instead of data. When that happens, log in again.

Unlike some APIs, the token is in the **response body**, so a LoT action can read it with `GET JSON "data.login.token"` and keep it internally (see Examples).

> [!WARNING]
>
> Keep the WinCC Unified user and password in Hub secrets and add them with `GET SECRET`. Never put them in the connector file or in retained topics. Restrict who may publish to the write and alarm topics: `writeTagValues` writes to the HMI tags and, through them, to the PLC.

## Configuration

* Replace `YOUR_WINCC_UNIFIED_HOST` in `BASE_ADDRESS` with the Runtime PC's host name or IP. That name must match the Runtime web server certificate. Keep `USE_SSL "true"`.
* Every event is `POST /graphql/` with `Content-Type: application/json`. The body is `{value.json.body}`, sent unchanged. Use GraphQL **variables** for values. That keeps quotes out of the query string and makes the payload easy to build in LoT.
* GraphQL answers HTTP `200` for most errors. Check the `errors` array (syntax, validation, not logged in) and, per item, `error.code`: `0` success, `2` cannot resolve name, `3` argument error, `201` cannot convert value to data type, `202` only leaf elements of a structure tag, `301` alarm filter syntax error, `302` / `303` invalid language, `304` / `305` alarm state does not allow the action.
* Tag names follow the WinCC Unified addressing rules, for example `HMI_Tag_1` or a structure element `Motor_1.Speed`. `BrowseTags` lists them with wildcards (`*`, `?`).
* `loggedTagValues` takes logging tag names (`Tag:LoggingTag`) or a tag name when that tag has only one logging tag. Set `startTime` or `endTime`. If you set only one of them, also set `maxNumberOfValues`. Timestamps are ISO 8601 UTC, for example `2026-10-05T07:00:00.000Z`.
* `activeAlarms` and `loggedAlarms` take an optional `filterString`. This is the WHERE part of a ChromQueryLanguage (SQL-like) filter, for example `Priority >= 10`. Alarm names are full alarm paths, for example `HMI_RT_1::Line1_Temperature:HighHigh`. `instanceID` `0` targets every instance.
* `writeTagValues` takes an optional `timestamp` and `quality` (`{"quality": "GOOD_CASCADE"}`) for the whole list, or per tag in `input`.

## Examples

Log in (publish to `historian/siemens-wincc-unified/session/create`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "body": {
    "query": "mutation Login($username: String!, $password: String!) { login(username: $username, password: $password) { token expires user { name fullName language autoLogoffSec } error { code description } } }",
    "variables": {
      "username": "<UMC user>",
      "password": "<password>"
    }
  }
}
```

Response on `historian/siemens-wincc-unified/session/create/response`:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"data": {"login": {"token": "<token>", "expires": "2026-10-05T07:30:00.000Z", "user": {"name": "operator", "fullName": "Operator", "language": "en-US", "autoLogoffSec": 1800}, "error": {"code": "0", "description": "Success"}}}}
```

Read live tag values (`historian/siemens-wincc-unified/tag-value/get`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "token": "<token>",
  "body": {
    "query": "query TagValues($names: [String!]!, $directRead: Boolean) { tagValues(names: $names, directRead: $directRead) { name value { value timestamp quality { quality subStatus } } error { code description } } }",
    "variables": {
      "names": [
        "Line1_Temperature",
        "Line1_Setpoint"
      ]
    }
  }
}
```

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"data": {"tagValues": [{"name": "Line1_Temperature", "value": {"value": 21.4, "timestamp": "2026-10-05T07:00:00.000Z", "quality": {"quality": "GOOD_CASCADE", "subStatus": "NON_SPECIFIC"}}, "error": {"code": "0", "description": "Success"}}]}}
```

Write a setpoint (`historian/siemens-wincc-unified/tag-value/update`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "token": "<token>",
  "body": {
    "query": "mutation WriteTagValues($input: [TagValueInput]!, $timestamp: Timestamp, $quality: QualityInput) { writeTagValues(input: $input, timestamp: $timestamp, quality: $quality) { name error { code description } } }",
    "variables": {
      "input": [
        {
          "name": "Line1_Setpoint",
          "value": 72.5
        }
      ]
    }
  }
}
```

Browse tags (`historian/siemens-wincc-unified/tag/browse`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "token": "<token>",
  "body": {
    "query": "query Browse($nameFilters: [String], $objectTypeFilters: [ObjectTypesEnum], $language: String) { browse(nameFilters: $nameFilters, objectTypeFilters: $objectTypeFilters, language: $language) { name displayName objectType dataType } }",
    "variables": {
      "nameFilters": [
        "Line1_*"
      ],
      "objectTypeFilters": [
        "TAG"
      ],
      "language": "en-US"
    }
  }
}
```

Read the last hour of a logging tag (`historian/siemens-wincc-unified/logged-tag-value/list`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "token": "<token>",
  "body": {
    "query": "query LoggedTagValues($names: [String]!, $startTime: Timestamp, $endTime: Timestamp, $maxNumberOfValues: Int, $sortingMode: LoggedTagValuesSortingModeEnum) { loggedTagValues(names: $names, startTime: $startTime, endTime: $endTime, maxNumberOfValues: $maxNumberOfValues, sortingMode: $sortingMode) { loggingTagName error { code description } values { value { value timestamp quality { quality subStatus } } flags } } }",
    "variables": {
      "names": [
        "Line1_Temperature:Line1_Temperature_Log"
      ],
      "startTime": "2026-10-05T06:00:00.000Z",
      "endTime": "2026-10-05T07:00:00.000Z",
      "maxNumberOfValues": 1000,
      "sortingMode": "TIME_ASC"
    }
  }
}
```

List active alarms with priority 10 or higher (`historian/siemens-wincc-unified/active-alarm/list`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "token": "<token>",
  "body": {
    "query": "query ActiveAlarms($systemNames: [String], $filterString: String, $filterLanguage: String, $languages: [String]) { activeAlarms(systemNames: $systemNames, filterString: $filterString, filterLanguage: $filterLanguage, languages: $languages) { name instanceID alarmGroupID raiseTime acknowledgmentTime clearTime resetTime modificationTime state priority eventText infoText alarmClassName origin area path value hostName userName } }",
    "variables": {
      "filterString": "Priority >= 10",
      "languages": [
        "en-US"
      ]
    }
  }
}
```

Acknowledge an alarm (`historian/siemens-wincc-unified/alarm/acknowledge`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "token": "<token>",
  "body": {
    "query": "mutation AcknowledgeAlarms($input: [AlarmIdentifierInput]!) { acknowledgeAlarms(input: $input) { alarmName alarmInstanceID error { code description } } }",
    "variables": {
      "input": [
        {
          "name": "HMI_RT_1::Line1_Temperature:HighHigh",
          "instanceID": 0
        }
      ]
    }
  }
}
```

Read logged alarms (`historian/siemens-wincc-unified/logged-alarm/list`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "token": "<token>",
  "body": {
    "query": "query LoggedAlarms($systemNames: [String], $filterString: String, $languages: [String], $startTime: Timestamp, $endTime: Timestamp, $maxNumberOfResults: Int) { loggedAlarms(systemNames: $systemNames, filterString: $filterString, languages: $languages, startTime: $startTime, endTime: $endTime, maxNumberOfResults: $maxNumberOfResults) { name instanceID raiseTime acknowledgmentTime clearTime resetTime modificationTime state priority eventText origin area } }",
    "variables": {
      "startTime": "2026-10-05T00:00:00.000Z",
      "endTime": "2026-10-05T07:00:00.000Z",
      "maxNumberOfResults": 100
    }
  }
}
```

Keep the session alive (`historian/siemens-wincc-unified/session/update`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "token": "<token>",
  "body": {
    "query": "mutation ExtendSession { extendSession { token expires error { code description } } }",
    "variables": {}
  }
}
```

Example actions: log in with Hub secrets, keep the token internally, keep the session alive, poll tags and alarms, write a setpoint and acknowledge alarms from MQTT. Send anything to `internal/wincc-unified/login` once to log in.

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
# Example actions for the WinccUnifiedGraphql route (docs page). Not part of the route template.
# Secrets: WINCC_UNIFIED_USER / WINCC_UNIFIED_PASSWORD = a UMC user configured for Runtime (read rights for queries,
#   write rights for writeTagValues and the alarm mutations). The login mutation returns the token in the response
#   BODY (data.login.token), so an action can keep it internally and add it to every request. The session stays
#   open while there is activity; the keep-alive below renews it. On an "errors" reply, publish to the login topic again.
# Tag and alarm names below are examples: use the names from your WinCC Unified project (BrowseTags lists them).

DEFINE ACTION WinccUnifiedLogin
ON TOPIC "internal/wincc-unified/login" DO
    SET "user" WITH GET SECRET "WINCC_UNIFIED_USER"
    SET "password" WITH GET SECRET "WINCC_UNIFIED_PASSWORD"
    PUBLISH TOPIC "historian/siemens-wincc-unified/session/create" WITH { "body": { "query": "mutation ($u: String!, $p: String!) { login(username: $u, password: $p) { token expires error { code description } } }", "variables": { "u": {user}, "p": {password} } } }

DEFINE ACTION WinccUnifiedRememberToken
ON TOPIC "historian/siemens-wincc-unified/session/create/response" DO
    SET "token" WITH GET JSON "data.login.token" IN PAYLOAD AS STRING
    KEEP TOPIC "internal/wincc-unified/token" WITH {token}

DEFINE ACTION WinccUnifiedKeepAlive
ON EVERY 5 MINUTES DO
    SET "token" WITH GET TOPIC "internal/wincc-unified/token"
    PUBLISH TOPIC "historian/siemens-wincc-unified/session/update" WITH { "token": {token}, "body": { "query": "mutation { extendSession { expires error { code description } } }" } }

DEFINE ACTION WinccUnifiedPollLine1
ON EVERY 10 SECONDS DO
    SET "token" WITH GET TOPIC "internal/wincc-unified/token"
    PUBLISH TOPIC "historian/siemens-wincc-unified/tag-value/get" WITH { "token": {token}, "body": { "query": "query ($names: [String!]!) { tagValues(names: $names) { name value { value timestamp quality { quality } } error { code description } } }", "variables": { "names": [ "Line1_Temperature", "Line1_Setpoint", "Line1_Running" ] } } }

DEFINE ACTION WinccUnifiedWriteSetpoint
ON TOPIC "plant/line1/setpoint/set" DO
    SET "token" WITH GET TOPIC "internal/wincc-unified/token"
    SET "value" WITH PAYLOAD AS DOUBLE
    PUBLISH TOPIC "historian/siemens-wincc-unified/tag-value/update" WITH { "token": {token}, "body": { "query": "mutation ($input: [TagValueInput]!) { writeTagValues(input: $input) { name error { code description } } }", "variables": { "input": [ { "name": "Line1_Setpoint", "value": {value} } ] } } }

DEFINE ACTION WinccUnifiedPollAlarms
ON EVERY 30 SECONDS DO
    SET "token" WITH GET TOPIC "internal/wincc-unified/token"
    PUBLISH TOPIC "historian/siemens-wincc-unified/active-alarm/list" WITH { "token": {token}, "body": { "query": "query ($languages: [String]) { activeAlarms(languages: $languages) { name instanceID state priority raiseTime eventText } }", "variables": { "languages": [ "en-US" ] } } }

DEFINE ACTION WinccUnifiedAcknowledgeFromMqtt
ON TOPIC "plant/line1/alarm/ack" DO
    SET "token" WITH GET TOPIC "internal/wincc-unified/token"
    SET "alarm" WITH GET JSON "name" IN PAYLOAD AS STRING
    PUBLISH TOPIC "historian/siemens-wincc-unified/alarm/acknowledge" WITH { "token": {token}, "body": { "query": "mutation ($input: [AlarmIdentifierInput]!) { acknowledgeAlarms(input: $input) { alarmName alarmInstanceID error { code description } } }", "variables": { "input": [ { "name": {alarm}, "instanceID": 0 } ] } } }
```

## Testing

Technical preview, not yet live-tested. The app package's smoke script parses and validates every preset GraphQL document (and every example on this page) against the WinCC Unified GraphQL schema, and checks the example variables against each document. It then runs every event against a local mock server that executes that schema. The mock run covers login, session, browse, read, write and read-back, logged values by logging tag and by tag name, active alarms with a filter, acknowledge (state changes to `RAISED_ACKNOWLEDGED`), reset, shelve / unshelve, disable / enable, logged alarms, extend session and logout. Negative controls cover a missing, bad or logged-out token, a wrong password (`101`), an unknown tag (`2`), a value that cannot be converted (`201`), an alarm that is already acknowledged (`305`), a bad alarm filter (`301`), logged values without a time range (`3`), an invalid document, a subscription over HTTP, and a write by a read-only user. There is no public WinCC Unified runtime, so no real server has been called. See `TEST.md` in the app package.

## Not covered

* **Subscriptions** (`tagValues`, `activeAlarms`, `reduState`). They need a WebSocket with the `graphql-transport-ws` protocol, which REST\_API connectors do not use. Poll `ReadTagValues` / `ListActiveAlarms` on a timer instead.
* `loginSWAC` (UMC SWAC single sign-on with `nonce` and a signed claim) and `identityProviderURL`. You can still send them through `GraphqlRequest`.
* Unified Comfort Panels, WinCC Unified Openness / ODK, and the Industrial Edge WinCC Unified apps.
* Engineering in TIA Portal (projects, screens, users). This connector only reads and writes runtime data.

## Related

* [REST API connectors](/latest/lot-language/routes/rest-api-routes)
* [REST API app catalog](/latest/lot-language/routes/rest-api-apps/index)
* [WinCC Unified GraphQL (RT Unified), V21](https://docs.tia.siemens.cloud/r/en-us/v21/wincc-unified-graphql-rt-unified)
* [WinCC Unified GraphQL requirements (RT Unified), V20](https://docs.tia.siemens.cloud/r/en-us/v20/wincc-unified-graphql-rt-unified/basics-rt-unified/requirements-rt-unified)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.