asyncapi: '2.0.0'
id: 'http://www.siemens.com/industry/edge/databus'
info:
  title: 'Siemens Industrial Edge Databus'
  version: '1.3.0'

servers:
  databusLocalNew:
    url: mqtt://ie-databus:1883
    protocol: mqtt
    description: The Industrial Edge Databus broker. New DNS name since Edge V1.1

  databusLocalDeprecated:
    url: mqtt://ie_databus:1883
    protocol: mqtt
    description: >
      The Industrial Edge Databus broker in V1.0.  Use 'databusLocalNew' for Edge versions >= 1.1.
      Support for the DNS name "ie_databus' will be removed in the next major version.

defaultContentType: application/json

channels:
  # Datapoint Metadata
  'ie/m/j/{msgStructureScheme}/{msgStructureSchemeMajorVersion}/{providerAppInstanceId}/dp':
    description: 'Datapoint Metadata of SIMATIC JSON payload format'
    parameters:
      msgStructureScheme:
        $ref: '#/components/parameters/msgStructureScheme'
      msgStructureSchemeMajorVersion:
        $ref: '#/components/parameters/msgStructureSchemeMajorVersion'
      providerAppInstanceId:
        $ref: '#/components/parameters/providerAppInstanceId'
    subscribe:
      operationId: subDpMetadataSimaticV1
      message:
        $ref: '#/components/messages/dpMetadataSimaticV1'
      bindings:
        mqtt:
          qos: 0
          retain: true

  # Datapoint values read json
  'ie/d/j/{msgStructureScheme}/{msgStructureSchemeMajorVersion}/{providerAppInstanceId}/dp/r{dpConnectionNamePath}{dpCollectionNamePath}':
    description: 'Datapoint values of SIMATIC JSON payload format for read'
    parameters:
      msgStructureScheme:
        $ref: '#/components/parameters/msgStructureScheme'
      msgStructureSchemeMajorVersion:
        $ref: '#/components/parameters/msgStructureSchemeMajorVersion'
      providerAppInstanceId:
        $ref: '#/components/parameters/providerAppInstanceId'
      dpConnectionNamePath:
        $ref: '#/components/parameters/dpConnectionNamePath'
      dpCollectionNamePath:
        $ref: '#/components/parameters/dpCollectionNamePath'
    subscribe:
      operationId: subDpValueSimaticV1
      message:
        $ref: '#/components/messages/subDpValueSimaticV1Msg'
      bindings:
        mqtt:
          qos: 0
          retain: false

  # Datapoint values write json
  'ie/d/j/{msgStructureScheme}/{msgStructureSchemeMajorVersion}/{providerAppInstanceId}/dp/w{dpConnectionNamePath}{dpCollectionNamePath}':
    description: 'Datapoint values of SIMATIC JSON payload format for write'
    parameters:
      msgStructureScheme:
        $ref: '#/components/parameters/msgStructureScheme'
      msgStructureSchemeMajorVersion:
        $ref: '#/components/parameters/msgStructureSchemeMajorVersion'
      providerAppInstanceId:
        $ref: '#/components/parameters/providerAppInstanceId'
      dpConnectionNamePath:
        $ref: '#/components/parameters/dpConnectionNamePath'
      dpCollectionNamePath:
        $ref: '#/components/parameters/dpCollectionNamePath'
    publish:
      operationId: pubDpValueSimaticV1
      message:
        $ref: '#/components/messages/pubDpValueSimaticV1Msg'
      bindings:
        mqtt:
          qos: 0
          retain: false

  # Diagnostic/Status Data (also 'last will' and 'birth')
  'ie/s/j/{msgStructureScheme}/{msgStructureSchemeMajorVersion}/{providerAppInstanceId}/status':
    description: |
      Status of the Connector and its Connections.
      Added in version 1.2.
    parameters:
      msgStructureScheme:
        $ref: '#/components/parameters/msgStructureScheme'
      msgStructureSchemeMajorVersion:
        $ref: '#/components/parameters/msgStructureSchemeMajorVersion'
      providerAppInstanceId:
        $ref: '#/components/parameters/providerAppInstanceId'
    subscribe:
      operationId: subDiagConnectorStatus
      message:
        $ref: '#/components/messages/diagConnectorStatusMsg'
      bindings:
        mqtt:
          qos: 0
          retain: true

  # Datapoint values binary
  'ie/d/b/simatic/v1/{providerAppInstanceId}/dp/r{dpConnectionNamePath}{dpCollectionNamePath}':
    description: 'Datapoint values of SIMATIC binary payload format for read'
    parameters:
      providerAppInstanceId:
        $ref: '#/components/parameters/providerAppInstanceId'
      dpConnectionNamePath:
        $ref: '#/components/parameters/dpConnectionNamePath'
      dpCollectionNamePath:
        $ref: '#/components/parameters/dpCollectionNamePath'
    subscribe:
      operationId: subDpValueSimaticBinaryV1
      message:
        $ref: '#/components/messages/subDpValueSimaticBinaryMsgV1'
    bindings:
      mqtt:
        qos: 0
        retain: false

  # Update request: re-send the last values (for late subscribers)
  'ie/c/j/{msgStructureScheme}/{msgStructureSchemeMajorVersion}/updaterequest':
    description: |
      Request to re-send the last values.
      Added in version 1.3.0.
    parameters:
      msgStructureScheme:
        $ref: '#/components/parameters/msgStructureScheme'
      msgStructureSchemeMajorVersion:
        $ref: '#/components/parameters/msgStructureSchemeMajorVersion'
    publish:
      operationId: pubUpdateRequest
      message:
        $ref: '#/components/messages/updateRequestMsg'
      bindings:
        mqtt:
          qos: 0
          retain: false

components:
  parameters:
    providerAppInstanceId:
      description: >
        The instance ID of an Edge App.
        The Instance ID might be prefixed by the name of an IED device which is
        separated using a colon (':') from the rest of the instance ID (e.g., "device15:s7c1").
        This prefix will be added when forwarding a message to another MQTT broker.
        That means the original instance name must not include a colon
        and also the device name must not include a colon.
      schema:
        type: string
        pattern: '^([^/#+:]+:)?[^/#+:]+$'
        examples:
          - "s7c1" # original instance name
          - "device15:s7c1" # instance name including device name prefix

    msgStructureSchemeMajorVersion:
      description: 'Major version of the SIMATIC payload schema version, prefixed by "v".'
      schema:
        $ref: '#/components/schemas/msgStructureSchemeMajorVersion'

    msgStructureScheme:
      description: 'Name of the JSON schema. Has to be "simatic" for the SIMATIC schema.'
      schema:
        $ref: '#/components/schemas/msgStructureScheme'

    dpConnectionNamePath:
      description: "The connection name of a connector, including the leading '/'."
      schema:
        type: string
        pattern: '^(/[^/#+]+)?$' # can be empty, but when non-empty must start with '/' and not contain any additional '/'
        examples:
          - "/PLC_1"

    dpCollectionNamePath:
      description: "The collection name of a connector, including the leading '/'."
      schema:
        type: string
        pattern: '^(/[^/#+]+)?$' # can be empty, but when non-empty must start with '/' and not contain any additional '/'
        examples:
          - "/default"

  messages:
    dpMetadataSimaticV1:
      name: dpMetadataSimaticV1
      contentType: application/json
      payload:
        $ref: "#/components/schemas/dpMetadataSimaticV1Payload"

    subDpValueSimaticV1Msg:
      name: subDpValueSimaticV1Msg
      contentType: application/json
      payload:
        oneOf:
          - $ref: "#/components/schemas/subDpValueSimaticV1Payload"
          - $ref: "#/components/schemas/subDpValueSimaticV11TimeSeriesPayload"

    pubDpValueSimaticV1Msg:
      name: pubDpValueSimaticV1Msg
      contentType: application/json
      payload:
        $ref: "#/components/schemas/pubDpValueSimaticV1Payload"

    diagConnectorStatusMsg:
      description: |
        Added in version 1.2
      name: subDiagConnectorStatusMsg
      contentType: application/json
      payload:
        $ref: "#/components/schemas/subDiagConnectorStatusPayload"

    subDpValueSimaticBinaryMsgV1:
      name: subDpValueSimaticBinaryMsgV1
      contentType: application/x-industrial-edge-databus-simatic-binary
      payload:
        $ref: "#/components/schemas/subDpValueSimaticBinaryV1Payload"

    updateRequestMsg:
      description: |
        Added in version 1.3.0
      name: pubUpdateRequestMsg
      contentType: application/json
      payload:
        $ref: "#/components/schemas/pubUpdateRequestPayload"

  schemas:
    dpMetadataSimaticV1Payload:
      description: "The Metadata root object."
      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
          description: |
            The official product name of the application. This is used for browsing
            purposes when a user selects a connector (e.g., from IIH Essentials or
            from OPC UA Server).
            Don't use this to programmatically check to which connector
            you are talking and don't make any assumptions about which
            features are supported based on this name.
            The name can change when a new product version is released, so don't rely
            on a longterm stability of this name.
            The length is limited to 60 characters.
            Added in version 1.2
          pattern: '^.{1,60}$'

        statustopic:
          description: |
            MQTT topic name of the connector + connection status.
            This is required when a connector supports the status topic.
            Added in version 1.2.
          type: string
          pattern: '^ie/s/j/simatic/v1/[^/]+/status$'
          examples:
            - "ie/s/j/simatic/v1/s7c1/status"

    dpMetaConnectionV1:
      description: "A connections object. What a connection is depends on the type of connector."
      type: object
      additionalProperties: false
      required:
        - name
        - type
        - dataPoints

      properties:
        name:
          description: "Name of the connection."
          type: string
          examples:
            - "PLC_1"
            - "Connection 1"

        type:
          description: "Type of the connection."
          type: string
          examples:
            - "s7"
            - "pn"

        dataPoints:
          description: "Datapoints of this connection."
          type: array
          items:
            $ref: "#/components/schemas/dpMetaDataPointCollectionV1"

    dpMetaDataPointCollectionV1:
      type: object
      additionalProperties: false
      required:
        - name
        - topic
        - dataPointDefinitions

      properties:
        name:
          description: "Name of the datapoint collection."
          type: string
          examples:
            - "default"

        topic:
          description: "MQTT topic name of the datapoint collection."
          type: string
          pattern: '^ie/d/(j|b|pb)/simatic/v1/[^/]+/dp/r(/[^/]+)?(/[^/]+)?$'
          examples:
            - "ie/d/j/simatic/v1/s7c1/dp/r/PLC_1/default"
            - "ie/d/j/simatic/v1/othdrv1/dp/r/connection5/collection12"
            - "ie/d/j/simatic/v1/othdrv2/dp/r/connection2"
            - "ie/d/j/simatic/v1/othdrv3/dp/r/collection7"
            - "ie/d/j/simatic/v1/pnhs1/dp/r"

        pubTopic:
          description: >
            MQTT topic name of the datapoint collection for writing to datapoints of the connector.
            This is required when any writeable datapoint is defined.
          type: string
          pattern: '^ie/d/(j|b|pb)/simatic/v1/[^/]+/dp/w(/[^/]+)?(/[^/]+)?$'
          examples:
            - "ie/d/j/simatic/v1/s7c1/dp/w/PLC_1"
            - "ie/d/j/simatic/v1/othdrv1/dp/w/connection5/collection12"
            - "ie/d/j/simatic/v1/othdrv2/dp/w/connection2"
            - "ie/d/j/simatic/v1/othdrv3/dp/w/collection7"
            - "ie/d/j/simatic/v1/pnhs1/dp/w"

        dataPointDefinitions:
          description: "Datapoints of this connection."
          type: array
          items:
            $ref: "#/components/schemas/dpMetaDataPointDefinitionV1"

        publishType:
          $ref: "#/components/schemas/dpMetaPublishTypeV1"

    dpMetaDataPointDefinitionV1:
      type: object
      additionalProperties: false
      required:
        - name
        - id
        - dataType

      properties:
        name:
          description: >
            Name of the datapoint. The name is only unique within a
            connection.
          type: string
          examples:
            - "Tag_1"
            - "Otto"
            - "ACME/Germany/Bavaria/Nuremberg/Moorenbrunn/Building7/Floor42/RoomD12/Station2/Robot4/Motor5/Temperature2"

        id:
          $ref: "#/components/schemas/dpId"

        dataType:
          $ref: "#/components/schemas/dpDataTypeV1"

        accessMode:
          $ref: "#/components/schemas/dpAccessmode"

        dataPointAddr:
          $ref: "#/components/schemas/dpDataPointAddr"

        valueRank:
          $ref: "#/components/schemas/arrayValueRank"

        arrayDimensions:
          $ref: "#/components/schemas/arrayArrayDimensions"

        sampleRateType:
          description: |
            Added in version 1.3.0
          $ref: "#/components/schemas/dpSampleRateType"

        sampleRateHz:
          description: |
            The static sample rate of the value. Only to be used, when the 'sampleRateType'
            in the metadata is set to 'static'.
            Added in version 1.3.0
          $ref: "#/components/schemas/dpSampleRateHz"

        acquisitionCycleInMs:
          description: "The acquisition cycle of the value in milliseconds. Can be a floating point number."
          type: number
          #format: double   # unfortunately this is not supported by my validator
          minimum: 0
          examples:
            - 1000
            - 1
            - 0.0625

        acquisitionMode:
          $ref: "#/components/schemas/dpAcquisitionMode"

    dpDataTypeV1:
      type: string
      oneOf:
        - const: 'Bool'
          description: "Boolean, mapped to JSON schema type 'integer' using the values 0 and 1"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_Bool"
        - const: 'Byte'
          description: >
            8-bit bit string, mapped to JSON schema type 'integer', range 0..255.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_Byte"
        - const: 'Word'
          description: >
            16-bit bit string, mapped to JSON schema type 'integer', range 0..65535.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_Word"
        - const: 'DWord'
          description: >
            32-bit bit string, mapped to JSON schema type 'integer', range 0..4294967295.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_DWord"
        - const: 'LWord'
          description: >
            64-bit bit string, mapped to JSON schema type 'string', range 0..18446744073709551615.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_LWord"
        - const: 'SInt'
          description: >
            8-bit integer, mapped to JSON schema type 'integer', range -128..127.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_SInt"
        - const: 'USInt'
          description: >
            8-bit unsigned integer, mapped to JSON schema type 'integer', range 0..255.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_USInt"
        - const: 'Int'
          description: >
            16-bit integer', mapped to JSON schema type 'integer', range -32768..32767.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_Int"
        - const: 'UInt'
          description: >
            16-bit unsigned integer, mapped to JSON schema type 'integer', range 0..65535.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_UInt"
        - const: 'DInt'
          description: >
            32-bit integer, mapped to JSON schema type 'integer', range -2147483648..2147483647.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_DInt"
        - const: 'UDInt'
          description: >
            32-bit unsigned integer, mapped to JSON schema type 'integer', range 0..4294967295.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_UDInt"
        - const: 'LInt'
          description: "64-bit integer, mapped to JSON schema type 'string', range -9223372036854775808..9223372036854775807"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_LInt"
        - const: 'ULInt'
          description: "64-bit unsigned integer, mapped to JSON schema type 'string', range 0..18446744073709551615"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_ULInt"
        - const: 'Real'
          description: >
            32-bit floating point, mapped to JSON schema type 'number'.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_Real"
        - const: 'LReal'
          description: >
            64-bit floating point, mapped to JSON schema type 'number'.
            Might also use JSON schema type 'string', but this is deprecated.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_LReal"
        - const: 'Char'
          description: "Unicode character, mapped to JSON schema type 'string'"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_Char"
        - const: 'String'
          description: "Unicode string, mapped to JSON schema type 'string'"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_String"
        - const: 'Time'
          description: >
            Time range in 100ns ticks as signed 64-bit integer, mapped to JSON schema type 'string'.
            The definition is the same as for 'LTime'. Newly developed connectors should only use the
            type 'LTime' and not use 'Time'.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_LTime"
        - const: 'LTime'
          description: "Time range in 100ns ticks as signed 64-bit integer, mapped to JSON schema type 'string'"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_LTime"
        - const: 'DateTime'
          description: "Date with Time (see definition of 'automationTimestamp'), mapped to JSON schema type 'string'"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_DateTime"
        - const: 'Date'
          description: "Date with Time (see definition of 'automationDate'), mapped to JSON schema type 'string'"
          x-dpDataType:
            $ref: "#/components/schemas/automationDate"
        - const: 'Time_Of_Day'
          description: >
            Time of day in 100ns ticks as signed 64-bit integer, mapped to JSON schema type 'string'.
            The definition is the same as for 'LTime_Of_Day'. Newly developed connectors should only use the
            type 'LTime_Of_Day' and not use 'Time_Of_Day'.
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_LTime_Of_Day"
        - const: 'LTime_Of_Day'
          description: "Time of day in 100ns ticks as signed 64-bit integer, mapped to JSON schema type 'string'"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_LTime_Of_Day"
        - const: 'Raw'
          description: "Raw data (binary blob) as base64 encoded string, mapped to JSON schema type 'string'"
          x-dpDataType:
            $ref: "#/components/schemas/dpDataType_Raw"

      examples:
        - "Word"
        - "UDInt"

    dpDataType_Bool:
      oneOf:
        - type: integer
          minimum: 0
          maximum: 1
        - type: string
          description: "It is deprecated to use a string for boolean values"
          oneOf:
            - const: '0'
            - const: '1'

    dpDataType_Byte:
      oneOf:
        - type: integer
          minimum: 0
          maximum: 255
        - type: string
          description: "It is deprecated to use a string for integers values"
          pattern: '^([0-9]|[1-9][0-9]|[0-1][0-9][0-9]|2[0-4][0-9]|25[0-5])$'

    dpDataType_Word:
      oneOf:
        - type: integer
          minimum: 0
          maximum: 65535
        - type: string
          description: "It is deprecated to use a string for integers (except for 64 bit integers)."
          pattern: '^([0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$'

    dpDataType_DWord:
      oneOf:
        - type: integer
          minimum: 0
          maximum: 4294967295
        - type: string
          description: "It is deprecated to use a string for integers (except for 64 bit integers)."
          pattern: '^([0-9]|[1-9][0-9]{1,9})$'

    dpDataType_LWord:
      description: >
        64 bit integers above 2^53-1 cannot be represented as integers in JSON, therefore strings have to be used.
        The value range encoded in the string can be from 0 to 18446744073709551615.
      oneOf:
        - type: integer
          minimum: 0
          maximum: 9007199254740991
        - type: string
          pattern: '^([0-9]|[1-9][0-9]{1,19})$'

    dpDataType_SInt:
      oneOf:
        - type: integer
          minimum: -128
          maximum: 127
        - type: string
          description: "It is deprecated to use a string for numbers (except for 64 bit integers)."
          pattern: '^(-)?([0-9]|[1-9][0-9]{1,2})$'

    dpDataType_USInt:
      oneOf:
        - type: integer
          minimum: 0
          maximum: 255
        - type: string
          description: "It is deprecated to use a string for numbers (except for 64 bit integers)."
          pattern: '^([0-9]|[1-9][0-9]|[0-1][0-9][0-9]|2[0-4][0-9]|25[0-5])$'

    dpDataType_Int:
      oneOf:
        - type: integer
          minimum: -32768
          maximum: 32767
        - type: string
          description: "It is deprecated to use a string for numbers (except for 64 bit integers)."
          pattern: '^(-)?([0-9]|[1-9][0-9]{1,4})$'

    dpDataType_UInt:
      oneOf:
        - type: integer
          minimum: 0
          maximum: 65535
        - type: string
          description: "It is deprecated to use a string for numbers (except for 64 bit integers)."
          pattern: '^([0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$'

    dpDataType_DInt:
      oneOf:
        - type: integer
          minimum: -2147483648
          maximum: 2147483647
        - type: string
          description: "It is deprecated to use a string for numbers (except for 64 bit integers)."
          pattern: '^(-)?([0-9]|[1-9][0-9]{1,9})$'

    dpDataType_UDInt:
      oneOf:
        - type: integer
          minimum: 0
          maximum: 4294967295
        - type: string
          description: "It is deprecated to use a string for numbers (except for 64 bit integers)."
          pattern: '^([0-9]|[1-9][0-9]{1,9})$'

    dpDataType_LInt:
      description: >
        64 bit integers above 2^53-1 cannot be represented as integers in JSON, therefore strings have to be used.
        The value range encoded in the string can be from -9223372036854775808 to 9223372036854775807.
      oneOf:
        - type: integer
          description: "It is deprecated to use a integer type for 64 bit integers, use type string instead."
          minimum: -9007199254740991
          maximum: 9007199254740991
        - type: string
          pattern: '^(-)?([0-9]|[1-9][0-9]{1,19})$'

    dpDataType_ULInt:
      description: >
        64 bit integers above 2^53-1 cannot be represented as integers in JSON, therefore strings have to be used.
        The value range encoded in the string can be from 0 to 18446744073709551615.
      oneOf:
        - type: integer
          description: "It is deprecated to use a integer type for 64 bit integers, use type string instead."
          minimum: 0
          maximum: 9007199254740991
        - type: string
          pattern: '^([0-9]|[1-9][0-9]{0,19})$'

    dpDataType_Real:
      oneOf:
        - type: number
        - type: string
          description: "It is deprecated to use a string for numbers (except for 64 bit integers)."
          #TODO: pattern missing

    dpDataType_LReal:
      oneOf:
        - type: number
        - type: string
          description: "It is deprecated to use a string for numbers (except for 64 bit integers)."
          #TODO: pattern missing

    dpDataType_Char:
      type: string
      pattern: '^.$'

    dpDataType_String:
      type: string

    dpDataType_LTime:
      description: >
        Time range in 100ns ticks as signed 64-bit integer.
        64 bit integer values above 2^53-1 cannot be represented as numbers in JSON,
        therefore strings have to be used.
        The value range encoded in the string can be from -9223372036854775808 to 9223372036854775807.
      oneOf:
        - type: integer
          description: "It is deprecated to use a integer type for 64 bit integers, use type string instead."
          minimum: -9007199254740991
          maximum: 9007199254740991
        - type: string
          pattern: '^(-)?([0-9]|[1-9][0-9]{1,19})$'

    dpDataType_DateTime:
      description: >
        Date with Time.
        Internally this is handled as number of 100 nanosecond intervals since January 1, 1601 (UTC).
      $ref: "#/components/schemas/automationTimestamp"

    dpDataType_Date:
      description: >
        Date without Time (all time components are 0).
        Internally this is handled as number of days since January 1, 1990 (UTC).
        This can held dates from 1990-01-01 to 2169-06-06.
      $ref: "#/components/schemas/automationDate"

    dpDataType_LTime_Of_Day:
      oneOf:
        - type: integer
          minimum: 0
          maximum: 863999999999
          description: "It is deprecated to use a integer type for 64 bit integers, use type string instead."
        - type: string
          pattern: '^(-)?([0-9]|[1-9][0-9]{1,11})$'
      description: >
        High resolution time of day in 100ns ticks as signed 64-bit integer.
        The possible range is from 0:00:00 to 23:59:59.9999999
      examples:
        - 121212443841
        - 434
        - 863999999999

    dpDataType_Raw:
      type: string
      pattern: "^[0-9a-zA-Z+/_-]*={0,2}$"
      description: >
        Raw byte array as base64 (RFC 4648) encoded string. Don't use newlines in the text.
      examples:
        - "YWJjZGVmZwo="
        - "MTIzNDUK"

    dpMetaPublishTypeV1:
      type: string
      oneOf:
        - const: 'bulk'
          description: >
            Bulk publish mode, contains values of multiple datapoints
            in every message.
          x-msgPayloadType:
            $ref: "#/components/schemas/subDpValueSimaticV1Payload"
        - const: 'timeseries'
          description: >
            Based on bulk mode, but contains multiple records from different points in time.
            Each record contains a collection of datapoints, that means there can be multiple
            of the same datapoint in one message.
          x-msgPayloadType:
          - $ref: "#/components/schemas/subDpValueSimaticV11TimeSeriesPayload"
        - const: 'binarytimeseries'
          description: >
            This is a binary data format for time series data. The structure is similar to
            the "timeseries" format, but the encoding is binary instead of JSON.
      default: 'bulk'
      examples:
        - "bulk"
        - "timeseries"

    subDpValueSimaticV1Payload:
      type: object
      additionalProperties: false
      required:
        - vals
      properties:
        seq:
          $ref: "#/components/schemas/sequenceNumber"

        ts:
          description: >
            Timestamp of the value collection. This is an optional element,
            it can be omitted when each data point is having it's own timestamp.
            It is highly recommended to use this global timestamp of the collection when all
            the data points published in the collection have same timestamp.
          $ref: "#/components/schemas/automationTimestamp"

        vals:
          description: "Array of data points published in the payload."
          type: array
          items:
            $ref: "#/components/schemas/dpSingleValueV1Payload"

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

        isResponseToUpdateRequest:
          description: |
            Added in version 1.3.0
          $ref: "#/components/schemas/isResponseToUpdateRequest"

    subDpValueSimaticV11RecPayload:
      type: object
      additionalProperties: false
      required:
        - vals
      properties:
        rseq:
          $ref: "#/components/schemas/recordSequenceNumber"

        ts:
          description: >
            Timestamp of the value collection. This is an optional element,
            it can be omitted when each data point is having it's own timestamp.
            It is highly recommended to use this global timestamp of the collection when all
            the data points published in the collection have same timestamp.
          $ref: "#/components/schemas/automationTimestamp"

        vals:
          description: "Array of data points published in the payload."
          type: array
          items:
            $ref: "#/components/schemas/dpSingleValueV1Payload"

    pubDpValueSimaticV1Payload:
      type: object
      additionalProperties: false
      required:
        - vals
      properties:
        seq:
          $ref: "#/components/schemas/sequenceNumber"

        vals:
          description: "Array of data points published in the payload."
          type: array
          items:
            $ref: "#/components/schemas/dpSingleValueV1Payload"

    subDiagConnectorStatusPayload:
      description: |
        Added in version 1.2.
      type: object
      additionalProperties: false
      required:
        - connector
      properties:
        seq:
          $ref: "#/components/schemas/sequenceNumber"

        ts:
          description: >
            Timestamp of the status message.
          $ref: "#/components/schemas/automationTimestamp"

        connector:
          $ref: "#/components/schemas/connectorStatus"

        connections:
          description: "Array connection status information."
          type: array
          items:
            $ref: "#/components/schemas/diagSingleConnection"

    connectorStatus:
      description: |
        Added in version 1.2.
      type: object
      additionalProperties: false
      required:
        - status
      properties:
        status:
          type: string
          oneOf:
            - const: 'good'
              description: >
                Connector is running, connections to Databus and
                underlying driver are established.
                This does NOT mean that the connections are all established. For the connection status check 'diagSingleConnection'.
            - const: 'bad'
              description: >
                Connector is running, but not fully functional.
            - const: 'available'
              description: >
                Connector started up and just established connection
                to Databus. Status of underlying driver and connections is not yet known.
                This is the "birth" message
            - const: 'unavailable'
              description: >
                Connector lost connection to Databus.
                This is the "last will" message.

        reason:
          type: string

    diagSingleConnection:
      description: |
        Added in version 1.2.
      type: object
      additionalProperties: false
      required:
        - name
        - status
      properties:
        name:
          description: "The name of the connection."
          type: string
          examples:
            - "PLC_1"

        status:
          type: string
          oneOf:
            - const: 'good'
              description: >
                Connection to device is up. Device is in running state.
            - const: 'stopped'
              description: >
                Connection to device is up. Device is in stopped state.
                Process data will not be updated in the device because user program it not running.
                Only System Alarms are available from some devices (e.g., S7-1500) and no alarms from other devices (e.g., S7-300).
            - const: 'bad'
              description: >
                Connection to device is down, communication to device will not work.

        reason:
          type: string

    sequenceNumber:
      description: >
        Sequence number. The number will monotonically increase until it
        reaches its maximum and then wrap around to 0. It can be used to
        detect missed messages.
        When a service restarts, this value can also start again at 0,
        it will not be persisted between restarts.
      type: integer
      minimum: 0
      maximum: 4294967295

    recordSequenceNumber:
      description: >
        Sequence number of a record. Not to mix up with the sequence
        number of the payload message. The record sequence number can be used to check if any record
        is missing. That number might come from underlying system and could
        be increased by more than one, e.g., when it contains a PROFINET
        CycleCounter it could be incremented by 4.
        The number will monotonically increase until it
        reaches its maximum and then wrap around to 0. It can be used to
        detect missed records but you need to know the algorithm how the
        value is increased.
        When a service restarts, this value can also start again at 0, the value is not persisted between restarts.
      type: integer
      minimum: 0
      maximum: 4294967295

    dpSingleValueV1Payload:
      type: object
      additionalProperties: false
      required:
        - id
        - val

      properties:
        id:
          description: "Datapoint identification as reference to the metadata."
          $ref: "#/components/schemas/dpId"

        val:
          description: >
            Value of the Tag. Has to fit to the data type of the data point
            defined in the metadata.
            The value can be a scalar value, an array or an object.
          $ref: "#/components/schemas/dpValueVariantType"

        ts:
          description: >
            Timestamp of the data point. Either use this attribute or the timestamp
            in the parent payload / record, but avoid to use both.
          $ref: "#/components/schemas/automationTimestamp"

        qc:
          description: "Quality of the value."
          $ref: "#/components/schemas/automationQuality"

        qx:
          description: |
            Extended quality of the value.
            Added in version 1.3.0.
          $ref: "#/components/schemas/automationQualityExtended"

        sampleRateHz:
          $ref: "#/components/schemas/dpSampleRateHz"
          description: |
            The dynamic sample rate of the value. Only to be used, when the 'sampleRateType'
            in the metadata is set to 'dynamic'.
            Added in version 1.3.0.

    dpId:
      description: >
        This is a reference between the properties "id" of the datapoint definition in the metadata
        and the property "id" in the datapoint value.
        This is a short string (at most 8 characters) to save bandwidth
        and performance because it needs to be transmitted for every datapoint value.
        When using numbers, omit leading zeros and use hexadecimal or base64 encoding
        to save some further bytes.
        The id is only unique within its connection.
        It is not long term stable and might change
        when anything is changed in the connector configuration.
      type: string
      pattern: '^.{1,8}$'
      examples:
        - "DP112"
        - "25"
        - "3AFE"

    automationQuality:
      type: integer
      oneOf:
        - const: 0
          description: 'BAD - The dp value is not useful'
        - const: 1
          description: 'UNCERTAIN - The quality of the dp value is less than normal, but the value may still be useful'
        - const: 2
          description: 'GOOD (non-cascade) - The quality of the dp value is good'
        - const: 3
          description: 'GOOD (cascade) - The quality of the dp value is good and may be used in control'

    automationQualityExtended:
      type: integer
      minimum: 0
      maximum: 65535
      description: |
        Extended quality information. This will only be set when one of
        the bits 14..8 or 5 to 0 is set because only then it contains
        additional information to 'qc'.
        Please refer to the additional documentation for Databus Payload
        for a more detailed description of the values.
        Here a brief summary:
        The lower 8 bits (bit 7..0) contain a Quality Code
        like from PROFIBUS PA / OPC DA.
        The bits 15..8 each are used as flag bits which means every single
        bit has its own meaning.
        bit 15: reserved. Ignore this bit value when you read it and
          set it to 0 when writing it. When you have an old value
          and modify some other bits then keep the previous state
          of this bit.
        bits 7..6: Quality. This is the same value as 'automationQuality'
        bits 5..2: Sub Status. The values depend on the 'Quality',
          that means there is a separate enumeration for each 'Quality' value.
        bits 1..0: Limits
        Added in version 1.2.

    automationTimestamp:
      type: string
      pattern: '^(160[1-9]|16[1-9][0-9]|1[7-9][0-9]{2}|[2-9][0-9]{3})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]{1,7})?Z$'
      #format: "date"  # the 'date' format doesn't fully match our needs with the high resolution!
      description: >
        High resolution ISO8601 based timestamp in UTC time zone.
        The resolution is 100 ns and the range is from 1601-01-01 to 9999-12-31.
        We expect the format yyyy-MM-ddTHH:MM:SS.sssssssZ where the
        decimal part can be omitted or otherwise must contain between 1 and 7 digits.
        The range and resolution comes from the OPC UA binary data type 'DateTime' as
        defined in part 6.
        Leap seconds (seconds=60) are not supported.
      examples:
        - "2020-11-23T16:35:41.1234567Z"
        - "1601-11-23T16:35:41.123Z"
        - "9999-11-23T16:35:41.1Z"
        - "2039-11-23T16:35:41Z"

    automationDate:
      type: string
      pattern: '^((((199[0-9]|20[0-9]{2}|21[0-6][0-8])-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]))|(2169-(0[1-5]-(0[1-9]|[1-2][0-9]|3[0-1])|(06-0[1-6]))))T00:00:00(\.0{1,7})?)Z$'
      description: >
        We expect the format yyyy-MM-ddT00:00:00.0000000Z where the
        decimal part can be omitted or otherwise must contain between 1 and 7 digits.
        The range is from 1990-01-01T00:00:00Z to 2169-06-06T00:00:00Z
      examples:
        - "2021-01-12T00:00:00Z"
        - "2020-11-23T00:00:00.0000000Z"
        - "1990-01-01T00:00:00Z"
        - "2169-06-06T00:00:00Z"

    dpValueVariantType:
      anyOf:
        - type: integer
        - type: number
        - type: string
        - type: array
          description: "Each array element is of type dpValueVariantType."
          # TODO: recursion doesn't work, at least not in html doc generation
          # see issue https://github.com/asyncapi/generator/issues/451
          #items:
          #  $ref: "#/components/schemas/dpValueVariantType"

    # parts of the channel name
    mqttPayloadType: # 'payloadType' in Wiki spec
      type: string
      oneOf:
        - const: 'm'
          description: 'metadata'
        - const: 'd'
          description: 'data'

    mqttPayloadEncoding: # 'encoding' in Wiki spec
      type: string
      oneOf:
        - const: 'j'
          description: 'JSON'
        - const: 'b'
          description: 'binary'
        - const: 'pb'
          description: 'Google protocol buffers'

    mqttPayloadMsgType: # 'payloadMsgType' in Wiki spec
      type: string
      oneOf:
        - const: 'dp'
          description: 'DataPoints for PLC Variables (process image)'
        - const: 'ev'
          description: 'Events (for Alarms, HMI Alarms, HMI Events)'

    msgStructureScheme:
      description: 'The name of the JSON schema. Can only be "simatic"'
      type: string
      const: 'simatic'
      examples:
        - "simatic"

    msgStructureSchemeMajorVersion: # 'msgStructureSchemeVersion' in Wiki spec
      description: 'The version of the JSON schema. Can only be "v1"'
      type: string
      const: 'v1'
      examples:
        - "v1"

    channelAccessmode: # 'accessmode' in Wiki spec
      type: string
      oneOf:
        - const: 'r'
          description: 'read from connectors'
        - const: 'w'
          description: 'write to connectors'

    subDpValueSimaticV11TimeSeriesPayload:
      type: object
      additionalProperties: false
      required:
        - records
      properties:
        seq:
          $ref: "#/components/schemas/sequenceNumber"

        records:
          type: array
          items:
            $ref: "#/components/schemas/subDpValueSimaticV11RecPayload"

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

        isResponseToUpdateRequest:
          description: |
            Added in version 1.3.0.
          $ref: "#/components/schemas/isResponseToUpdateRequest"

    isResponseToUpdateRequest:
      type: boolean
      description: |
        When the message is a response to an update-request then this value is set to true.
        Otherwise it is omitted from the message.
        Added in version 1.3.0.

    pubUpdateRequestPayload:
      type: object
      additionalProperties: false
      description: |
        This message is sent by the client to request an update selected datapoints with different granularity.
        The connector (or gateway) will respond with a message containing the requested datapoints.
        The topic name will be the same topic which is also used for the normal data publish messages.
        The payload of the response message will contain the requested datapoints and the flag
        'isResponseToUpdateRequest' will be set to true in this message to make it possible to distinguish it
        from an ordinary data message.
        Older connectors might not support this message and will ignore it. Some will not support the empty string, but require
        at least the connector name to be includes in the 'Path' attribute (e.g., the "SIMATIC S7 Connector").
        The Connectivity Suite Databus Gateway supports all forms of the 'Path' attribute.
        Added in version 1.3.0.
      properties:
        Path:
          description: >
            The scope of the update request. This can have one of the following forms:
            1. empty string: The update request is for all connectors, all connections and all their collections
            2. connector name: The update request is for one connector, all connections of the connector and all their collections
            3. connector name and connection name: The update request is for one connector and one of its connections and all its collections
            4. connector name, connection name and collection name: The update request is for one single collection of one connection in one connector
            The elements are separated by a slash character.
          type: string
          examples:
            - "" # global update request
            - "css7pdriver1" # connector specific update request
            - "css7pdriver1/Connection1" # connection specific update request
            - "css7pdriver1/Connection1/100ms" # collection specific update request

    subDpValueSimaticBinaryV1Payload:
      type: object
      additionalProperties: false
      format: binary
      # TODO: define the binary format

    metadataHashVersion:
      description: >
        Hash value to identify the version of the metadata.
        When the metadata contains information which is required
        by the client to interpret the payload (like for binary encoding),
        then this value is required.
        The "mdHashVer" field of the dpValue payload has to match the
        "hashVersion" number in the metadata definition.
        Don't expect this number to be monotonically increasing on changes.
      type: integer
      minimum: 0
      maximum: 4294967295

    dpAccessmode:
      type: string
      oneOf:
        - const: 'r'
          description: 'read-only dp'
        - const: 'w'
          description: 'write-only dp'
        - const: 'rw'
          description: 'read-write dp'
      default: 'r'
      examples:
        - 'rw'
        - 'r'
        - 'w'

    dpDataPointAddr:
      description: >
        This is specifically needed for binary encoded payload to describe the structure
        of the payload, that means which tag can be found at which byte/bit position in the
        binary payload. It has nothing to do with the address of the source of the item
        (e.g., an address within a PLC).
      type: string
      examples:
        - "S4A5.3"
        - "S0A0"
        - "S6A6[4]"

    arrayValueRank:
      description: >
        This attribute indicates whether the val attribute of the datapoint is an
        array and how many dimensions the array has.
      type: integer
      default: -1
      examples:
        - 2
      oneOf:
        - const: -1
          description: 'Scalar: The value is not an array.'
        - const: 0
          description: 'OneOrMoreDimensions: The value is an array with one or more dimensions.'
        - const: 1
          description: 'OneDimension: The value is an array with one dimension.'
        - const: 2
          description: 'The value is an array with two dimensions.'
        - const: 3
          description: 'The value is an array with three dimensions.'
        - const: 4
          description: 'The value is an array with four dimensions.'
        - const: 5
          description: 'The value is an array with five dimensions.'
        - const: 6
          description: 'The value is an array with six dimensions.'
        - const: 7
          description: 'The value is an array with seven dimensions.'
        - const: 8
          description: 'The value is an array with eight dimensions.'
        - const: 9
          description: 'The value is an array with nine dimensions.'
        - const: 10
          description: 'The value is an array with ten dimensions.'
        - const: -3
          description: 'ScalarOrOneDimension: The value can be a scalar or a one dimensional array.'
        - const: -2
          description: 'Any: The value can be a scalar or an array with any number of dimensions.'

    arrayArrayDimensions:
      description: >
        This attribute specifies the maximum supported length of each dimension.
        If the maximum of a dimension is unknown the value shall be 0.
        The number of elements shall be equal to the value of the ValueRank attribute.
        This attribute shall be omitted if ValueRank <= 0.
      type: array
      items:
        type: integer
        minimum: 0
      examples:
        - [3, 5]

    dpAcquisitionMode:
      type: string
      # we cant't limit it to an enumeration with specific values
      examples:
        - 'CyclicOnChange'
        - 'CyclicOnContinuous'

    dpSampleRateType:
      type: string
      oneOf:
        - const: 'static'
          description: 'The sample rate value is defined in the metadata and is identical for all messages.'
        - const: 'dynamic'
          description: 'The sample rate value is defined in the payload and can be different for all messages.'
      description: |
        "sample rate" in the payload format is the concept of providing many values
        of the same variable with the smallest possible overhead. This is used for
        high frequency data like audio, vibration or motion control.
        There is only one timestamp for an array of sampled values and the values are sampled
        with a fixed time. The sample rate value is used to calculate the time stamps
        of the array elements.
        The first item is from the accompanying timestamp, the second item is from the timestamp
        plus 1/sampleRate.
        The sample rate type defines if the sample rate value is defined in the metadata
        or in the payload. The value is used to determine where to find the sample rate value.
        Here an example:
          val[] = [10, 11, 12, 13]
          sample_rate = 1000Hz => sample period=1/sample_rate=1/1000Hz=1ms
          record timestamp =     2022-02-22T10:00:00.000
          value[0]=10 sampled at 2022-02-22T10:00:00.000 (same as record timestamp)
          value[1]=11 sampled at 2022-02-22T10:00:00.001 (record timestamp + 1*sample period)
          value[2]=12 sampled at 2022-02-22T10:00:00.002 (record timestamp + 2*sample period)
          value[3]=13 sampled at 2022-02-22T10:00:00.003 (record timestamp + 3*sample period)
        Added in version 1.3.0.

    dpSampleRateHz:
      type: number
      minimum: 0
      description: |
        The sample rate value in Hz, this means samples per second (1/s).
        The data type is a floating point number.
        The value 0 is reserved for future usage.
        See also 'sampleRateType'.
        Added in version 1.3.0.
      examples:
        - 0.1
        - 10.01
        - 1000
        - 48000