The chat responses are generated using Generative AI technology for intuitive search and may not be entirely accurate. They are not intended as professional advice. For full details, including our use rights, privacy practices and potential export control restrictions, please refer to our Generative AI Service Terms of Use and Generative AI Service Privacy Information. As this is a test version, please let us know if something irritating comes up. Like you get recommended a chocolate fudge ice cream instead of an energy managing application. If that occurs, please use the feedback button in our contact form!
Skip to content

Industrial Edge is an open, ready-to-use edge computing platform, with edge devices, edge applications (apps) and connectivity through an integrated app and device management infrastructure.

Industrial Edge Common Databus Payload Format

This document describes the more general concepts about the payload format which didn't fit in the asyncapi.yaml itself.

Please check the change log for the change history.

API Definition as a Contract

The IE Common Databus Payload Async API spec is a contract which allows many variations. As long as a connector is fulfilling the contract, it is considered to be compliant, even when it changes its behavior from one version to another one.

For example, numeric values are no longer quoted in the SIMATIC S7 Connector V1.2. The API spec allows both, the quoted and the unquoted variant, but the quoted one is deprecated. This is considered a non-breaking change because both variations are allowed and all clients should be prepared to handle both variants.

This means clients need to:

  • Implement against the API (and not against example messages)
  • Test against example messages

Some hints about the implementation

  • Don’t make any assumption about the content of the “id” field (don’t assume you get the tag name there or that the value is numeric)
  • Don’t make any assumption about the applicationName. Products names often change. To identify a connector instance, use the providerAppInstanceId which is part of every topic name, e.g. mbtcp1 in the topic ie/m/j/simatic/v1/mbtcp1/dp for the Modbus TCP Connector. On Industrial Edge there is currently no concept for multiple instances of a connector type. When such a concept will be implemented, further instances will be named mbtcp2, mbtcp3, etc.
  • Be prepared that numbers might be quoted as strings or might be actual numbers (the quoted variant is deprecated, and all connectors shall switch to the non-quoted numbers)
  • 64-bit integer values are special because they cannot be exactly represented by the JavaScript 'Number' datatype and many libraries for other languages have the same problem (that's why we use strings to represent such numbers)
  • There are at least two kinds of payloads for the cyclic values which need to be supported both: bulk (subDpValueSimaticV1Payload) and time series (subDpValueSimaticV11TimeSeriesPayload). The Databus Gateway for Connectivity Suite connectors uses the time series format, because it is more compact and efficient, the Simatic S7 Connector and other legacy connectors will use the bulk format.
  • Expect that the OPC UA Connector uses real arrays instead of using pipe-separated values in strings
  • Timestamps might miss the fractional seconds part, e.g. "2025-11-05T07:16:06" instead of "2025-11-05T07:16:06.182440Z" or can have less than 7 fractional digits like "2025-11-05T07:16:06.182Z". They always need the "Z" at the end to make sure UTC timezone is meant and the "T" to be conformant to ISO8601.
  • Check the chapters about scope and lifetime of datapoint IDs and names below

Implementing Subsets

Most connectors are based on the Connectivity Suite framework and only support the newer "timeseries" publish type. Old connectors like the SIMATIC S7 Connector user the “bulk” publish type which is considered outdated because it has more overhead. Some connectors, for example the PROFINET IO Connector, only support timeseries or binarytimeseries.

Not all connectors support all data types. That means, only a subset of the possible features is implemented by a specific connector.

Each connector needs to document which subsets are implemented and which API version is implemented. This is important for clients if they did not implement all the features, for example the timeseries publish type.

Compatibility Rules

When the minor version of the payload schema changes, only optional fields (example: qx) are added to an object and only new alternative objects are added.

Many fields are not formally required, because they have been added after V1.1.0, but newer versions of the connectors shall support them (e.g. pubTopic, hashVersion, qx).

Some parts of the API spec are marked as deprecated (e.g. encoding numbers as strings). New connectors shall not use any deprecated fields and existing ones shall consider to remove them in newer releases.

The “v1” as major version in the topic name means we could add a new version “v2” in parallel but the effort of doing this is too high, so we do everything to avoid that. The performance of notifying all values twice would also be very bad.

Meaning of the API Version

Semantic versioning is being used, that means:

  • In case of a breaking change, the major version will be changed
  • Changes in the minor version are optional additions (new fields in existing messages or new message types)

The version of the Common Payload API is in principle independent of the IE Platform and IE App versions. That means, when there are no changes for a new Industrial Edge release, there won’t be a new API version. This also means that a connector might still implement according to an older version of the API.

Metadata Message Handling

Metadata messages need to set the retain=true flag for the MQTT message. This is needed to make the metadata available to clients which connect at a later time.

To know which messages are supported, you need to check which topics are defined in the metadata. For example to know if the write response which was introduced in V1.4.0 is supported, you check for the value of pubResponseTopic because you need it anyhow to receive the response.

When to publish this message?

  1. When the connector starts
  2. When the MetaData has changed
  3. When the connector has lost the connection to the DataBus and reconnects. This is needed because the DataBus might have been restarted and lost the value. Please refer also to the fields mdHashVer and hashVersion of the AsyncAPI definition for more information.

Value Message Handling

Value messages should set the retain=false flag for the MQTT message. This improves the performance and avoids that clients work with outdated values.

There might be some specific connectors for which the retain=true flag is reasonable but they should be aware that the retain values are not preserved when the Databus restarts and needs to be refreshed from time to time.

QoS

In case of the local MQTT message bus, the QoS setting shall be always "0" because TCP guarantees that no messages are lost between the publisher and the broker. The additional guarantees of higher QoS values are not existent when no persistent buffering is implemented.

QoS=1 and QoS=2 add a lot of additional overhead and reduce the throughput. In high load scenarios, instead of guaranteeing message delivery, this instead leads to an earlier collapse of the system because of the higher load and is therefore counterproductive.

In case a proxy is between the publisher and the Databus or when they are running on a different machine and the network or machine might fail, the situation might become different.

Connector Specific Messages

Some connectors (e.g. the PROFINET IO Connector) implement additional specific messages which are not part of the common API spec. Those are defined in an extra asyncapi.yaml (e.g. asyncapi_profinet_io_conn.yaml).

Default Values

Values which are identical to the default values can be omitted, the client just uses the default value.

Unexpected Behaviour

Publish Mode bulk

In some cases (e.g. when the CPU load is high), the 'bulk' format might contain the same datapoint multiple times from a different point in time.

Case Sensitive / Case Insensitive

Keys of JSON messages are always case sensitive. When it is not explicitly described, all other values are case sensitive. This applies especially for datapoints and data type names as well as for enum values.

Messages on the Databus

The supported messages on the Databus are defined in the 'asyncapi.yaml' file under channels

Here a condensed overview about the most important messages:

  'ie/m/j/simatic/v1/{providerAppInstanceId}/dp':
    description: 'Datapoint Metadata of SIMATIC JSON payload format'

  'ie/d/j/simatic/v1/{providerAppInstanceId}/dp/r{dpConnectionNamePath}{dpCollectionNamePath}':
    description: 'Datapoint values of SIMATIC JSON payload format for cyclic read (subscriptions)'

  'ie/d/j/simatic/v1/{providerAppInstanceId}/dp/w{dpConnectionNamePath}{dpCollectionNamePath}':
    description: 'Datapoint values of SIMATIC JSON payload format for write requests'

  'ie/d/j/simatic/v1/{providerAppInstanceId}/dp/wr/resp{dpConnectionNamePath}{dpCollectionNamePath}':
    description: |
      Datapoint values of SIMATIC JSON payload format for write responses.
      Added in version 1.4.0.

  'ie/d/j/simatic/v1/{providerAppInstanceId}/dp/sr/req/{dpConnectionNamePath}{dpCollectionNamePath}':
    description: |
      Datapoint values of SIMATIC JSON payload format for single read requests.
      Added in version 1.4.0.

  'ie/d/j/simatic/v1/{providerAppInstanceId}/dp/sr/resp/{dpConnectionNamePath}{dpCollectionNamePath}':
    description: |
      Datapoint values of SIMATIC JSON payload format for single read responses
      Added in version 1.4.0.

  'ie/s/j/simatic/v1/{providerAppInstanceId}/status':
    description: |
      Status of the connector and its connections.
      Added in version 1.2.

  'ie/c/j/simatic/v1/updaterequest':
    description: |
      Request to re-send the last values.
      Added in version 1.3.0.

To find the content definition of the messages, follow the $ref to the message. The best way is to use a yaml capable editor which allow navigating along the ref. We typically use Visual Studio code with the 'YAML' extension from Red Hat.

Here the message ref for the metadata:

message:
  $ref: '#/components/messages/dpMetadataSimaticV1'

and here the definition of its message dpMetadataSimaticV1 :

dpMetadataSimaticV1:
  description: |
    Allowed to be 'null' in version 1.4.0 for the shutdown or uninstallation of a connector.
  name: dpMetadataSimaticV1
  contentType: application/json
  payload:
    oneOf:
      - type: "null"
      - $ref: "#/components/schemas/dpMetadataSimaticV1Payload"

There might be more than one payload message type allowed here. Metadata, status and all other topics which use retain=true allow an empty message (type null) for removal of that message from the broker in shutdown scenarios.

The single-read and the write have a success and global error message:

payload:
  oneOf:
    - $ref: "#/components/schemas/subSingleReadResponseDpValueSimaticV1Payload"
    - $ref: "#/components/schemas/subSingleReadResponseGlobalErrorDpValueSimaticV1Payload"

In dpMetadataSimaticV1Payload you can see what properties are allowed and which are mandatory (check the required array). Most important are the description fields which give additional information (omitted here for brevity):

dpMetadataSimaticV1Payload:
  type: object
  additionalProperties: false
  required:
    - connections

  properties:
    seq:
      $ref: "#/components/schemas/sequenceNumber"

    hashVersion:
      $ref: "#/components/schemas/metadataHashVersion"

    connections:
      type: array
      items:
        $ref: "#/components/schemas/dpMetaConnectionV1"

    applicationName:
      type: string
      pattern: '^.{1,60}$'

    statustopic:
      type: string
      pattern: '^ie/s/j/simatic/v1/[^/]+/status$'
      examples:
        - "ie/s/j/simatic/v1/s7c1/status"

Metadata

The starting point is always to subscribe to the MetaData to get the mapping from the DataPoint names to their IDs and also to get the needed topics to access the values or the status of a connector. You can subscribe to ie/m/j/simatic/v1/# to get all MetaData of all connectors and also use that to find the active connectors.

Cyclic reading of Datapoint Values

The topics under ie/d/j/simatic/v1/{providerAppInstanceId}/dp/r contain the cyclically updated values. There are two different update modes:

  • CyclicOnChange: Only the Datapoint values which have changed are contained in a message
  • CyclicOnContinuous: All Datapoint values are contained in all published messages

Some connectors allow to configure the mode (e.g. per connection), others work in a fixed mode.

To find out which topic you need to subscribe to get the values of a specific Datapoint, check out the Metadata.

Re-publish the last published values of all Datapoints (update-request)

When a connector uses the update mode CyclicOnChange, you typically have the issue that you missed the first message when a connector started up and your client will miss some slow-changing and constant values. To get the initial state for such a subscription, you can send an update-request message.

This causes a re-publish of the last value of all subscribed DataPoints. The value will not be re-read from the device, instead the latest cached value together with the original timestamp and quality will be re-published under the original topic.

That update message contains the property "isResponseToUpdateRequest":true so that a client can distinguish the update from a normal cyclic message. Normally you would ignore all responses that you didn't ask for, e.g. only accept the first one and after that ignore all following ones.

The response message will be received by all clients so you should be careful only to request it when you really need it, that means typically after you subscribe to a new topic. Don't call this cyclically because that could overload your system!

Single reading of Datapoint values

"Single-read" is the term we used to distinguish from the cyclic read which is more a subscription. It is a simple request-reply which goes directly to the connector and reads the datapoint value from there. It doesn't use the value which might be cached in the Databus Gateway.

There are DataPoints where it makes no sense to read them cyclically, e.g. recipe data or setpoints. For such use cases you can configure the DataPoint in the connector, but don't set the "Publish to Databus" and the "acquisition cycle" in the configuration.

This will cause the DataPoint to be put into the nonCyclicDataPoints section of the MetaData. There you can find its ID and datatype. The ID can be used to do a single-read or a write. You can also do a single-read of DataPoints which are subscribed.

You can find the request and response topics in the Metadata, here an example:

  • request: "singleReadRequestTopic" : "ie/d/j/simatic/v1/mbtcp1/dp/sr/req/s7"
  • response: "singleReadResponseTopic" : "ie/d/j/simatic/v1/mbtcp1/dp/sr/resp/s7"

Example Command

Get the Metadata and extract the read request (singleReadRequestTopic) and response (singleReadResponseTopic) topic from the metadata.

mosquitto_sub -u edge -P edge -h ie-databus.proxy-redirect -t "ie/m/j/simatic/v1/mbtcp1/dp" -F '%j' | jq '.payload? | fromjson'

output from MetaData topic:

{
  "applicationName": "Modbus TCP Connector (Siemens AG)",
  "statustopic": "ie/s/j/simatic/v1/mbtcp1/status",
  "connections": [
    {
      "name": "s7",
      "type": "cs-modbustcp",
      "dataPoints": [
        {
          "name": "1000ms",
          "topic": "ie/d/j/simatic/v1/mbtcp1/dp/r/s7/1000ms",
          "pubTopic": "ie/d/j/simatic/v1/mbtcp1/dp/w/s7",
          "pubResponseTopic": "ie/d/j/simatic/v1/mbtcp1/dp/wr/resp/s7",
          "singleReadRequestTopic": "ie/d/j/simatic/v1/mbtcp1/dp/sr/req/s7",
          "singleReadResponseTopic": "ie/d/j/simatic/v1/mbtcp1/dp/sr/resp/s7",
          "publishType": "timeseries",
          "dataPointDefinitions": [
            {
              "name": "Counter1",
              "id": "1",
              "dataType": "UInt",
              "accessMode": "rw",
              "acquisitionCycleInMs": 1000
            },
            {
              "name": "Counter2",
              "id": "2",
              "dataType": "UInt",
              "accessMode": "rw",
              "acquisitionCycleInMs": 1000
            }
          ]
        }
      ],
      "nonCyclicDataPoints": {
        "pubTopic": "ie/d/j/simatic/v1/mbtcp1/dp/w/s7",
        "pubResponseTopic": "ie/d/j/simatic/v1/mbtcp1/dp/wr/resp/s7",
        "singleReadRequestTopic": "ie/d/j/simatic/v1/mbtcp1/dp/sr/req/s7",
        "singleReadResponseTopic": "ie/d/j/simatic/v1/mbtcp1/dp/sr/resp/s7",
        "dataPointDefinitions": [
          {
            "name": "Counter1000",
            "id": "3",
            "dataType": "UInt",
            "accessMode": "rw"
          }
        ]
      }
    }
  ],
  "seq": 2,
  "hashVersion": 3165959619
}

Start a subscription to the response topic:

singleReadResponseTopic="ie/d/j/simatic/v1/mbtcp1/dp/sr/resp/s7"
mosquitto_sub -u edge -P edge -h ie-databus.proxy-redirect -t "$singleReadResponseTopic" -F '%j' | jq '.payload? | fromjson'

Execute the single-read command in another shell:

singleReadRequestTopic="ie/d/j/simatic/v1/mbtcp1/dp/sr/req/s7"
mosquitto_pub -u edge -P edge -h ie-databus.proxy-redirect -t "$singleReadRequestTopic" -m '{"requestId":"myclient-112371", "ids": ["1", "3"]}'

output from response topic when everything is ok:

{
  "requestId": "myclient-112371",
  "mdHashVer": 3165959619,
  "records": [
    {
      "rseq": 10,
      "ts": "2025-11-04T15:19:53.4950688Z",
      "vals": [
        {
          "id": "1",
          "qc": 3,
          "val": 16286
        },
        {
          "id": "3",
          "qc": 3,
          "val": 0
        }
      ]
    }
  ]
}

output from response topic when there is a global error because the request is malformed:

{
  "mdHashVer": 0,
  "globalError": {
    "resultCode": 11,
    "errorMessage": "Missing mandatory 'requestId' in 'Read Request'"
  }
}

output from response topic when there is at least one datapoint specific errors (see rejected):

{
  "requestId": "myclient-112371",
  "mdHashVer": 3165959619,
  "records": [
    {
      "rseq": 12,
      "ts": "2025-11-05T07:16:06.1819445Z",
      "vals": [
        {
          "id": "3",
          "qc": 3,
          "val": 299
        }
      ]
    }
  ]
  "rejected": [
    {
      "id": "1",
      "resultCode": 6,
      "errorMessage": "ID is not a string"
    }
  ]
}

Writing of Datapoint values

Since API version V1.4.0 there is an optional response for the write message. To get that response, you need to provide the requestId property. Without it, there will be no response. This ensures compatibility with older versions and allows for faster performance when the response is not used anyway.

There are DataPoints where it makes no sense to read them cyclically, but still want to write them. For such use cases you can configure the DataPoint in the connector, but don't set the "Publish to Databus" and the "acquisition cycle" in the configuration.

This will cause the DataPoint to be put into the nonCyclicDataPoints section of the MetaData. There you can find its ID and datatype. The ID can be used to do a single-read or a write.

You can find the request and response topics in the Metadata, here an example:

  • request: "pubTopic" : "ie/d/j/simatic/v1/mbtcp1/dp/w/s7"
  • response: "pubResponseTopic" : "ie/d/j/simatic/v1/mbtcp1/dp/wr/resp/s7"

Example command

Get the Metadata and extract the write request (pubTopic) and response (pubResponseTopic) topic from the metadata.

mosquitto_sub -u edge -P edge -h ie-databus.proxy-redirect -t "ie/m/j/simatic/v1/mbtcp1/dp" -F '%j' | jq '.payload? | fromjson'

output from MetaData topic:

{
  "applicationName": "Modbus TCP Connector (Siemens AG)",
  "statustopic": "ie/s/j/simatic/v1/mbtcp1/status",
  "connections": [
    {
      "name": "s7",
      "type": "cs-modbustcp",
      "dataPoints": [
        {
          "name": "1000ms",
          "topic": "ie/d/j/simatic/v1/mbtcp1/dp/r/s7/1000ms",
          "pubTopic": "ie/d/j/simatic/v1/mbtcp1/dp/w/s7",
          "pubResponseTopic": "ie/d/j/simatic/v1/mbtcp1/dp/wr/resp/s7",
          "singleReadRequestTopic": "ie/d/j/simatic/v1/mbtcp1/dp/sr/req/s7",
          "singleReadResponseTopic": "ie/d/j/simatic/v1/mbtcp1/dp/sr/resp/s7",
          "publishType": "timeseries",
          "dataPointDefinitions": [
            {
              "name": "Counter1",
              "id": "1",
              "dataType": "UInt",
              "accessMode": "rw",
              "acquisitionCycleInMs": 1000
            },
            {
              "name": "Counter2",
              "id": "2",
              "dataType": "UInt",
              "accessMode": "rw",
              "acquisitionCycleInMs": 1000
            }
          ]
        }
      ],
      "nonCyclicDataPoints": {
        "pubTopic": "ie/d/j/simatic/v1/mbtcp1/dp/w/s7",
        "pubResponseTopic": "ie/d/j/simatic/v1/mbtcp1/dp/wr/resp/s7",
        "singleReadRequestTopic": "ie/d/j/simatic/v1/mbtcp1/dp/sr/req/s7",
        "singleReadResponseTopic": "ie/d/j/simatic/v1/mbtcp1/dp/sr/resp/s7",
        "dataPointDefinitions": [
          {
            "name": "Counter1000",
            "id": "3",
            "dataType": "UInt",
            "accessMode": "rw"
          }
        ]
      }
    }
  ],
  "seq": 2,
  "hashVersion": 3165959619
}

Start a subscription to the response topic:

pubResponseTopic="ie/d/j/simatic/v1/mbtcp1/dp/wr/resp/s7"
mosquitto_sub -u edge -P edge -h ie-databus.proxy-redirect -t "$pubResponseTopic" -F '%j' | jq '.payload? | fromjson'

Execute the write command in another shell:

pubTopic="ie/d/j/simatic/v1/mbtcp1/dp/w/s7"
mosquitto_pub -u edge -P edge -h ie-databus.proxy-redirect -t "$pubTopic" -m '{"requestId":"myclient-90210", "vals": [{"id":"1", "val":123}, {"id":"3", "val":299}]}'

output from response topic when everything was fine:

{
  "requestId": "myclient-90210",
  "mdHashVer": 3165959619,
  "status": [
    {
      "id": "1",
      "resultCode": 0
    },
    {
      "id": "3",
      "resultCode": 0
    }
  ]
}

output from response topic when there is a global error because the request is malformed:

{
  "requestId": "myclient-90210",
  "mdHashVer": 0,
  "globalError": {
    "resultCode": 10,
    "errorMessage": "Failed to read vals of 'Write Request'"
  }
}

output from response topic when there is at least one datapoint specific errors (see resultCode not 0):

{
  "requestId": "myclient-90210",
  "mdHashVer": 3165959619,
  "status": [
    {
      "id": "1",
      "resultCode": 6,
      "errorMessage": "ID is not a string"
    },
    {
      "id": "3",
      "resultCode": 16,
      "errorMessage": "invalid argument for given datatype"
    }
  ]
}

Status of a connector and its connections

There is a status topic 'ie/s/j/simatic/v1/{providerAppInstanceId}/status' for each connector. It contains information about the connector itself which only tells if the connector is running. When the connector status is "good" it doesn't mean that the connection states are also good, those need to be evaluated separately.

When displaying the status of a connector as one traffic light, you should merge the states of the connector and all connections in the following way:

  • connector state=="good" and all connection states=="good" => green
  • connector state=="good" and any connection state!="good" => yellow
  • connector state=="bad" => red

Example status message:

{
  "seq": 5,
  "ts": "2025-11-04T15:09:17.7235090Z",
  "connector": {
    "status": "good",
    "reason": "CS-Connector up and running"
  },
  "connections": [
    {
      "name": "s7",
      "status": "good",
      "reason": "ok"
    }
  ]
}

Quality Information

There can be two types of quality information for each datapoint value:

  • qc: only 4 major states
  • qx: available since API V1.2

qx contains additional information compared with qc, for example sub-states for the qualities and some single bit flags.

TL;DR Very Short Introduction

  • the good value for qc is 3
  • the good value for the lower 8 bits of qx is 192 (hexadecimal 0xc0) or 128 (hexadecimal 0x80). That means you always need to mask the value with 255 (hexadecimal 0xff) before comparing because the bits 8 to 15 might be also set when the value is good
  • all other values mean bad or uncertain

For more details how to evaluate or set qc/qx and the complete definition see below.

qc

This is a small subset of qx (actually the bits 7+6 of qx).

qc can have one of the following numeric values:

  • 0 : BAD - The dp value is not useful
  • 1 : UNCERTAIN - The quality of the dp value is less than normal but the value may still be useful
  • 2 : GOOD (non-cascade) - The quality of the dp value is good
  • 3 : GOOD (cascade) - The quality of the dp value is good and may be used in control

qx

qx is an extension of qc which is 15 bits long instead of 2 bits. The Definition has been copied from WinCC UA.

In the following, the overview of the qx structure:

  • High Byte: Industrial Edge Specific Information
    • Bit 15: Reserved
    • Bit 14...12: Flags
    • Bit 11...8: Extended sub-status
  • Low Byte: Quality code according to PROFIBUS PA / OPC DA
    • Bit 7...6: Quality
    • Bit 5...2: Sub-status
    • Bit 1...0: Limits

Evaluation of qc/qx in a consumer App

qx will be only added to a message, if it contains additional information to qc. That means, when any of the bits 14 to 8 or 5 to 0 is non-zero. As a consumer, if you would like to use the additional information of qx, you should do the following in your code to simplify the evaluation and to take care if the qx field is not there but just the qc field as fallback:

uint16_t qx;
if(val.hasField("qx") {
    qx = val.getFieldValue("qx");
} else {
    // qx doesn’t exist, use qc as fallback and convert it to same structure as qx
    qx = val.getFieldValue("qc") << 6;
}
// work just with value of qx
if(qx & 0x80) { // qx is either 'Good' or 'Good (cascade)'
    ...
}

Quality Code

The tables below reflect the quality, sub-status codes, and limit description of the quality code which is encoded in the low-byte of Industrial Edge quality attributes.

Quality
Value of bits 7..6 (decimal)QualityDescription
0BADThe value is not useful for reasons indicated by the sub-status.
1UNCERTAINThe quality of the value is less than normal but the value may still be useful. The reason is indicated by the sub-status.
2GOOD (non-cascade)The quality of the value is good.
3GOOD (cascade)The quality of the value is good and may be used in control.

Only sub-status codes are listed that are assigned by the IE Connector. Sub-status codes assigned by the PLC and/or periphery only are not listed but reserved to provide peripheral status codes.

Sub-status for Quality "BAD"
Value of bits 5..2 (decimal)"BAD" sub-statusDescription
0Non-specificThere is no specific reason why the value is BAD.
1Configuration errorThe value is not useful because of some inconsistency regarding the configuration.
2Not connectedThe value is not reliable because the connection to the provider has been disconnected at consumer-side (e.g. a communication driver actively disconnects from a PLC on user request or by design).
4Sensor failureThe value is not useful because it cannot be converted, i.e. a value from the device (PLC) cannot be converted to the corresponding HMI tag.
5No communication, with last usable valueThe value is not useful because the communication to the data source failed, however a last known value is available.
6No communication, no usable valueThe value is not useful because the communication to the data source failed or has never been established since it was last out of service and a last known value is not available.
7Out of serviceThe value is not reliable because the provider side has been disabled or shut-down (e.g. a PLC is in stop mode, or a tag is disabled for maintenance purposes).

For further "BAD" sub-status codes assigned by PLC/periphery only, refer to PROFIBUS-PA.

Sub-status for Quality "UNCERTAIN"
Value of bits 5..2 (decimal)"UNCERTAIN" sub-statusDescription
0Non-specificThere is no specific reason why the value is UNCERTAIN.
1Last usable valueThe connection to the data source is still established, however the data source stopped updating the value for some reason.
2Substitute valueA predefined value is used in case of an invalid value due to communication issues with the data source or a range violation. The reason for providing substitute values is configurable.
3Initial valueA predefined value intended for the startup of the HMI system (or a sub-ordinate device) is used while not being able to provide values from the data source.
5Range violationThe value lies outside the range defined by the min. and max. value. The limits define which direction (min. or max.) has been exceeded.
6Sub-normalA value derived from multiple values has less than the required number of good sources. This includes data aggregation by means of data compression algorithms.

For further “UNCERTAIN” sub-status codes assigned by PLC/periphery only, refer to PROFIBUS-PA.

Sub-status for Quality "GOOD (cascade)"
Value of bits 5..2 (decimal)"GOOD (cascade)" sub-statusDescription
0Non-specificNo error or special condition is associated with this value.
6Local overrideThe value has been overridden by the user or some logic in to continue operation. Typically, the input has been disconnected and a manually entered value has been 'forced', or a value has been corrected.

For further "GOOD" (non-cascade and cascade) sub-status codes assigned by PLC/periphery only, refer to PROFIBUS-PA.

Limits
Value of bits 1..0 (decimal)"Limit"Description
0OkData quality unrelated to limits.
1Low limit violationThe value has exceeded its low limit.
2High limit violationThe value has exceeded its high limit.
3ConstantThe value cannot move, no matter what the process is doing.

Industrial Edge specific Quality Information

The tables below reflect the extended sub-status and flag description of the quality code which is Industrial Edge specific and encoded in the high-byte of Industrial Edge quality attributes. The intention of Industrial Edge specific extended sub-status is to describe the data quality more distinct than the sub-status according to PROFIBUS-PA. Nevertheless, to support 3rd party collaboration based on standards only, a best-effort sub-status is always set, even if a more distinct extended sub-status is present.

Extended sub-status "BAD"
Value of bits 11..8 (decimal)Extended sub-status "BAD"Description
0Non-specificNo Industrial Edge specific extended bad sub-status is associated with this value.
1Aggregated valueThe value has been calculated out of multiple values with less than the required number of good sources. This includes data aggregation by means of data compression algorithms. The corresponding sub-status is set to ‘non-specific’.
3Unusable valueA (logged) value has been identified to be incorrect but a respective correction value is not available. The corresponding sub-status is set to ‘non-specific’.
7DisabledThe provider of the value (e.g. logging tag for logged value) has been disabled and the previous value was BAD. The corresponding sub-status is taken from the last (previous) sub-status.
Extended sub-status "UNCERTAIN"
Value of bits 11..8 (decimal)Extended sub-status "UNCERTAIN"Description
0Non-specificNo Industrial Edge specific extended uncertain sub-status is associated with this value.
1Aggregated valueThe value has been calculated out of multiple values with less than the required number of good sources to be GOOD as well as less than required number of bad sources to be BAD. This includes data aggregation by means of data compression algorithms. The corresponding sub-status is set to ‘sub-normal’.
7DisabledThe provider of the value (e.g. logging tag for logged value) has been disabled and the previous value was GOOD or UNCERTAIN. In case of GOOD, the corresponding sub- status is set to ‘last usable value’. In case of UNCERTAIN, the corresponding sub-status is taken from the last (previous) sub-status.
Extended sub-status "GOOD (cascade)"
Value of bits 11..8 (decimal)Extended sub-status "GOOD (cascade)"Description
0Non-specificNo Industrial Edge specific extended good sub-status is associated with this value.
1Aggregated valueThe value has been calculated out of multiple (good) values. This includes data aggregation by means of data compression algorithms. The corresponding sub-status is set to ‘non-specific’.
2Manual inputA (logged) value has been created manually. The corresponding sub-status is set to ‘non-specific’.
3Corrected valueA (logged) value has been corrected. The corresponding sub-status is set to ‘non-specific’.
6Initial valueThe local data source has been initialized with the configured initial value. The corresponding sub-status is set to ‘non-specific’.
Extended sub-status "GOOD (non-cascade)"

Please note that Industrial Edge doesn’t define extended sub-status for good (non-cascade).

Flags
Bit NumberExtended sub-status "GOOD (cascade)"Description
Bit 12Source qualityThe data quality has been determined and assigned by external data source.
Bit 13Source timeThe data timestamp has been produced and assigned by external data source.
Bit 14Time correctedThe data timestamp applied by external data source has been corrected by the system. Thus, Bit 13 “Source time” is not set. Time correction happens if the external timestamp is older than the timestamp of the last known value.
Bit 15ReservedIgnore when reading, set to 0 when creating, preserve when copying

Overview of Message Formats

The following tables should give an overview about the different message types.

Defined in Common Databus Payload API (asyncapi.yaml)

These definitions are common for all connectors.

Data Point Payload Format for read/subscribe

publishTypeMessage TypeMessage Example in principleUsed by connector
singleData Point Payload (deprecated since V1.2, no longer supported for new installations){ seq, val, ts, qc }SIMATIC S7 V1.1, Modbus TCP V1.0, Ethernet IP V1.0
bulkData Points Payload (subDpValueSimaticV1Payload){ seq, (ts), vals[ { id, val, ts, qc, (qx) } ] }SIMATIC S7 V1.1/V1.2, PROFINET IO V1.0.2 (no oversampling), Modbus TCP V1.0, Ethernet IP V1.0
timeseriesData Points Time Series Payload (subDpValueSimaticV11TimeSeriesPayload){ seq, records[ { ts, rseq, vals[ { id, val, qc } ] } ] }PROFINET IO V1.0.2 (with oversampling)
binarytimeseriesData Points Binary Payload (subDpValueSimaticBinaryMsgV1). Binary raw format with almost same content then “timeseries” format.{ seq, records[ { ts, rseq, vals[ { id, val, qc } ] } ] } Currently only defined in user documentation of PROFINET IO Connector, not yet in asyncapi.PROFINET IO V1.0.2 (with oversampling)

Data Point Payload Format for write/publish

publishTypeMessage TypeMessage Example in principleUsed by connector
singleData Point Payload (deprecated since V1.2, no longer supported for new installations){ seq, vals{ id, val, ts, qc } }SIMATIC S7 V1.1, Modbus TCP V1.0, Ethernet IP V1.0
bulkData Points Payload (pubDpValueSimaticV1Payload){ seq, vals[ { id, val, ts, qc } ] }SIMATIC S7 V1.1/V1.2, PROFINET IO 1.1, Modbus TCP V1.0, Ethernet IP V1.0

PROFINET IO specific Payload Formats

These messages are part of the Common Payload API but are defined in the separate file asyncapi_profinet_io_conn.yaml. They are specific for PROFINET and are only supported by the PROFINET IO Connector. Even in future, probably no other connector will implement them.

Message TypeMessage Example in principleUsed by connector
Read PROFINET Records request{ (seq), reqs[ { laddr, index} ] }PROFINET IO 1.1
Read PROFINET Records response{ (seq), rsps[ { (laddr), (index), (val), status, (errorDescription), ts} ] }PROFINET IO 1.1
Write PROFINET Records request{ (seq), reqs[ { laddr, index, val} ] }PROFINET IO 1.1
Write PROFINET Records response{ (seq), rsps[ { (laddr), (index), status, (errorDescription), ts} ] }PROFINET IO 1.1

Private Messages not defined in Common Databus Payload API

These messages are local extensions of the connectors and are not part of the Common Databus API definition. That means, they have not been standardized in the Common Databus Payload API. The main reason is that the maturity level is not high enough to ensure that the definition will not change. In future versions of the API, they might be included but there may be some changes in the content or even the topic name. If a connector implements such private extensions, it probably must change the implementation when the message gets part of the Common Payload API with a changed content and also must define a transition strategy for clients which use the private extension. Client Apps should be aware that those private extensions have a higher chance of being changed than those of the Common Payload API messages.

Other Payload Formats for read/subscribe

Message TypeMessage Example in principleUsed by connector
Connection and Disconnection Status (not yet part of common payload){ id, msg }SIMATIC S7 V1.1/V1.2
Alarms{ seq, evs[ { area, clsName, evTxt[ ], evTxtExt[ ], id, … } ] }SIMATIC S7 V1.1/V1.2

Scope of Datapoint Names

The scope of a datapoint name is a connection. That means within a connection the name must be unique.

Scope of the IDs

The scope of a datapoint id is the connector instance. That means within a connector instance the id must be unique.

Lifetime of the IDs and when do they change?

When the Metadata is updated, the IDs can change. The metadata is only published on change (with retain=true), that means when you subscribe to it and receive an update you need to update your internal name to ID map.

There is a field called hashVersion in the metadata which needs to match mdHashVer in several messages, e.g. for cyclic value updates and single reads and writes. When the values don't match, then your stored version of the metadata is outdated and needs to be updated. The mapping from id to name might have been changed in the new metadata.

This is a synchronized way to know exactly which metadata version was used for which data message because the update of the metadata and data MQTT topics is asynchronously and maybe the notification order between Metadata message and Value message could be reversed (see also the sequence diagram below).

Sequence Diagrams

App Startup and Configuration Update

sequenceDiagram
    participant EdgeRuntime
    participant Connector
    participant Databus
    participant App

    EdgeRuntime ->> Databus : Start
    EdgeRuntime ->> Connector : Start
    Connector ->> Connector : Read configuration (hashVer=0x4567)
    Connector ->> Databus : Connect and Login
    Connector ->> Databus : Publish Metadata (retain=true, hashVer=0x4567)
    Connector ->> Databus : Publish Values(retain=false, seq=1, hashVer=0x4567)
    EdgeRuntime ->> App : Start
    App ->> Databus : Subscribe for Metadata and Values
    Databus ->> App : Notify Metadata (retain=true, hashVer=0x4567)
    App ->> App: Build Name <=> Id Map
    Connector ->> Databus : Publish values(retain=false, seq=2, hashVer=0x4567)
    Databus ->> App : Notify Values(retain=false, seq=2, hashVer=0x4567)
    Connector ->> Databus : Publish values(retain=false, seq=3, hashVer=0x4567)
    Databus ->> App : Notify Values(retain=false, seq=3, hashVer=0x4567)
    Connector ->> Connector : Detected Configuration Change
    Connector ->> Connector : Restart
    Connector ->> Connector : Read changed Configuration (hashVer=0x7825)

    alt normal case: Metadata notification arrives before first Value notification
      Connector ->> Databus : Publish Metadata (retain=true, hashVer=0x7825) (new hash)
      Databus ->> App : Notify Metadata (retain=true, hashVer=0x7825)
      App ->> App: Build Name <=> Id Map
      Connector ->> Databus : Publish Values(retain=false, seq=1, hashVer=07825) (seq restarts)
      Databus ->> App : Notify Values(retain=false, seq=1, hashVer=0x7825)
    else inversion of message notification order: Value before new Metadata
      Connector ->> Databus : Publish Metadata (retain=true, hashVer=0x7825) (new hash)
      Connector ->> Databus : Publish Values(retain=false, seq=1, hashVer=07825) (seq restarts)
      Databus ->> App : Notify Values(retain=false, seq=1, hashVer=0x7825) (requires updated metadata: ignore or put on hold)
      Databus ->> App : Notify Metadata (retain=true, hashVer=0x7825)
      App ->> App: Build Name <=> Id Map
    end

Conformance Testing / Validation

Not-Conforming Connectors

Legacy OPC UA connector

The legacy OPC UA connector uses arrays packed into a string where the values are separated by pipe characters, e.g. “10 | 21 | 33”. This fails the validation because this is not an integer value (not even a quoted one).

Legacy Ethernet IP and Modbus Connectors

These connectors used Boolean values using “TRUE” and “FALSE” instead of 1 and 0.

WinCC Unified MQTT adapter

The WinCC Unified MQTT adapter uses IDs longer than the allowed 8 characters (e.g. “1.0.1000.2.0.0”).