> For the complete documentation index, see [llms.txt](https://docs.cybus.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.cybus.io/2-4-2/guides/system-connectivity/mes-erp-business-systems/critical-manufacturing-mes-integration.md).

# Critical Manufacturing MES Integration

This guide describes how to integrate Critical Manufacturing MES (CM MES) with Connectware. You configure a service commissioning file that sends shop floor data to CM MES through its REST API and receives data from MES workflows in return. A complete example file is available at the end of this guide.

## Objectives

* Establishing an OAuth-authenticated connection between Connectware and the CM MES REST API through the Security Portal.
* Posting data collection results from the shop floor to CM MES.
* Polling a MES business object at a regular interval.
* Calling any CM MES service operation on demand.
* Receiving data from CM MES workflows in Connectware.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* Access to a CM MES instance, including its hostname and the tenant name configured for the environment.
* A client ID and client secret registered in the Critical Manufacturing Security Portal for the OAuth 2.0 client credentials flow, or a long-term access token such as a Personal Access Token (PAT). The MES user behind the credentials needs the roles required for the services you call.
* Access to the REST API catalog of your CM MES installation, which contains the OpenAPI specification of every service. A public version is available in the [CM MES REST API Reference](https://developer.criticalmanufacturing.com/11.2/reference/api-rest/index.html).
* Access to the [Admin UI](/2-4-2/access/admin-ui.md) with sufficient [user permissions](/2-4-2/access/user-management.md).
* Basic knowledge of MQTT and the Connectware [services](/2-4-2/data-flows/services.md) concept (for example, [service commissioning files](/2-4-2/data-flows/service-commissioning-files.md), [connections](/2-4-2/data-flows/service-commissioning-files/resources/cybus-connection.md), and [endpoints](/2-4-2/data-flows/service-commissioning-files/resources/cybus-endpoint.md)).

## Connectware and CM MES Integration

CM MES exposes all of its functionality as REST services under the `/api` path of the MES instance, following the pattern `https://<mesHost>/api/<ServiceName>/<Operation>`. For example, the DataCollection service lives under `/api/DataCollection`. Connectware communicates with these services through the [HTTP/REST connector](/2-4-2/connectors/enterprise-connectors/http-rest.md).

The CM MES REST API is remote-procedure style. Almost every operation is an HTTP POST request that takes a JSON input object and returns a JSON output object. A few lookup operations, such as `GetObjectByName` of the GenericService, are HTTP GET requests with query parameters. This shape determines which Connectware endpoint operation you use:

* `write` endpoints send POST requests and cover the vast majority of MES operations, both commands and queries.
* `subscribe` endpoints poll GET operations at a regular interval.

Authentication is handled by the Critical Manufacturing Security Portal, an OAuth 2.0 identity provider that is part of every MES installation. Connectware retrieves a bearer token with the [OAuth 2.0 Client Credentials Grant](https://docs.cybus.io/2-4-2/guides/system-connectivity/mes-erp-business-systems/pages/Hij6TsDxB4GxfyynBwLn#oauth-2.0-client-credentials-grant) and renews it automatically. For details on the flow, see [How the Security Portal works](https://help.criticalmanufacturing.com/11.2/operationguide/system-administration/security/security-portal/security_portal_howdoesitwork/) in the Critical Manufacturing documentation.

{% hint style="info" %}
The input and output objects of the MES services are versioned business object structures that differ between MES versions and installations. Take the exact request schema for each operation from the REST API catalog of your installation. To discover which service the MES UI calls for a given task, record the network traffic in your browser developer tools while performing the task and look for requests with the `/api/` prefix.
{% endhint %}

The MQTT topics in this guide follow an ISA-95-style equipment hierarchy (`<enterprise>/<site>/<area>/<line>/<cell>`). The mappings subscribe with wildcards across all levels, so any machine in the hierarchy is picked up without changing the integration.

### CM MES Connection Properties

The connection to CM MES requires the hostname, the tenant name, and the OAuth client credentials. We add them as parameters to the service commissioning file, so you can set them when you install the service.

Do not worry about copying the service commissioning file snippets together into one, the complete example file is available at the end of this guide.

* `mesHost`: The hostname of your CM MES instance, without the scheme. For example, `mes.example.com`.
* `mesTenant`: The tenant name configured on your MES environment. It is part of the Security Portal token URL.
* `oauthClientId` and `oauthClientSecret`: The client credentials registered in the Security Portal.
* `mesObjectType` and `mesObjectName`: The type and name of the MES business object that the polling example reads. Defaults to the `Material` named `LOT-0001`.
* `pollInterval`: The polling interval for MES object data in milliseconds.
* `topicRoot`: The root of the MQTT topic hierarchy. Defaults to `enterprise`.

{% code lineNumbers="true" %}

```yaml
parameters:
  mesHost:
    description: Hostname of your Critical Manufacturing MES instance
    type: string
    default: mes.example.com

  mesTenant:
    description: Tenant name configured on your MES environment
    type: string
    default: ExampleTenant

  oauthClientId:
    description: Client ID registered in the Security Portal
    type: string

  oauthClientSecret:
    description: Client secret registered in the Security Portal
    type: string

  mesObjectType:
    description: Object type of the MES business object to poll
    type: string
    default: Material

  mesObjectName:
    description: Name of the MES business object to poll
    type: string
    default: LOT-0001

  pollInterval:
    description: Polling interval for MES object data in milliseconds
    type: integer
    default: 60000

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise
```

{% endcode %}

### CM MES Connection

To connect to the CM MES REST API, we set up a `Cybus::Connection` resource that uses the HTTP/REST connector with the OAuth 2.0 client credentials flow. The token endpoint of the Security Portal is `https://<mesHost>/SecurityPortal/api/tenant/<mesTenant>/oauth2/token`. Connectware fetches the bearer token from this endpoint, sends it in the `Authorization` header of every request, and refreshes it before it expires. The endpoints that use this connection do not need any authentication configuration of their own.

{% code lineNumbers="true" %}

```yaml
resources:
  mesConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: !ref mesHost
        port: 443
        oauthClientCredentials:
          auth_url: !sub 'https://${mesHost}/SecurityPortal/api/tenant/${mesTenant}/oauth2/token'
          client_id: !ref oauthClientId
          client_secret: !ref oauthClientSecret
```

{% endcode %}

If you cannot register a client for the client credentials flow, you can authenticate with a long-term access token instead, for example a PAT created in the MES. In this case, replace the `oauthClientCredentials` property with a static `headers` property:

{% code lineNumbers="true" %}

```yaml
connection:
  scheme: https
  host: !ref mesHost
  port: 443
  headers:
    Authorization: !sub 'Bearer ${mesAccessToken}'
```

{% endcode %}

Connectware does not renew a static header token. Use a token with a sufficient lifetime and rotate it before it expires.

### Posting Data Collection Results

The `PostDataCollectionPoints` operation of the DataCollection service writes collected values, such as measurements or test results, against a data collection instance in the MES.

We define a write endpoint for the operation path and a mapping that feeds it from the MQTT topic hierarchy. The HTTP/REST connector expects the request body in the `body` property of the message (see [Publishing Data to REST Servers](/2-4-2/connectors/enterprise-connectors/http-rest.md#publishing-data-to-rest-servers)). The `transform` rule wraps the incoming payload accordingly, so machines can publish their data without knowing about this convention.

{% code lineNumbers="true" %}

```yaml
dataCollectionEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref mesConnection
    write:
      path: /api/DataCollection/PostDataCollectionPoints

dataCollectionMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/data-collection'
        publish:
          endpoint: !ref dataCollectionEndpoint
        rules:
          - transform:
              expression: '{ "body": $ }'
```

{% endcode %}

Any message published to a matching topic, for example `enterprise/hamburg/assembly/line-1/press-01/data-collection`, now results in one POST request to the MES. The payload must match the `PostDataCollectionPointsInput` object of your MES version, which references the data collection instance and the points to add. The following structure is a placeholder that shows the general shape, take the exact schema and the required references from the REST API catalog of your installation:

{% code lineNumbers="true" %}

```json
{
  "DataCollectionInstance": {
    "...": "reference to the open data collection instance"
  },
  "DataCollectionPoints": [{ "Name": "TEMPERATURE", "Value": 42.1 }]
}
```

{% endcode %}

### Polling MES Object Data

For reading MES data continuously, the GenericService provides the GET operation `GetObjectByName`, which loads any MES business object by its type and name. A subscribe endpoint polls this operation at a regular interval and a mapping publishes the response to an MQTT topic.

{% code lineNumbers="true" %}

```yaml
objectInfoEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref mesConnection
    subscribe:
      path: /api/GenericService/GetObjectByName
      interval: !ref pollInterval
      query:
        Type: !ref mesObjectType
        Name: !ref mesObjectName

objectInfoMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref objectInfoEndpoint
        publish:
          topic: !sub '${topicRoot}/mes/object-info'
```

{% endcode %}

With the default parameters, Connectware requests the `Material` object named `LOT-0001` every 60 seconds and publishes the response, wrapped in a `timestamp` and `value` structure, to `enterprise/mes/object-info`.

### Calling Any MES Service Operation

CM MES exposes hundreds of operations across its services, and defining one endpoint per operation does not scale for integrations that call many of them. Since the HTTP/REST connector supports [dynamic paths for publishing](/2-4-2/connectors/enterprise-connectors/http-rest.md#dynamic-path-for-publishing), one generic write endpoint on the `/api` base path covers them all. The message provides the operation path in the `pathAppend` property and the input object in the `body` property.

{% code lineNumbers="true" %}

```yaml
mesRequestEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref mesConnection
    write:
      path: /api

mesRequestMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/mes/request'
        publish:
          endpoint: !ref mesRequestEndpoint
```

{% endcode %}

For example, the following message published to `enterprise/mes/request` calls the `LogObjectEvent` operation of the GenericService. The MES response is published to the `/res` topic of the endpoint.

{% code lineNumbers="true" %}

```json
{
  "pathAppend": "/GenericService/LogObjectEvent",
  "body": {
    "...": "input object of the operation"
  }
}
```

{% endcode %}

### Receiving Data from the MES

For the return direction, Connectware hosts an HTTP route using the `Cybus::Server::Http` and `Cybus::Node::Http` resources. A mapping publishes every request body that arrives on this route to an MQTT topic, where any other Connectware service can pick it up, for example to write an acknowledgment back to a PLC.

{% code lineNumbers="true" %}

```yaml
mesEventServer:
  type: Cybus::Server::Http
  properties:
    basePath: /cm-mes

mesEventRoute:
  type: Cybus::Node::Http
  properties:
    parent: !ref mesEventServer
    method: POST
    route: /events

mesEventMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref mesEventRoute
        publish:
          topic: !sub '${topicRoot}/cm-mes/events'
```

{% endcode %}

The route is served under the `/data` prefix of your Connectware instance: `https://<connectware>/data/cm-mes/events`. On the MES side, any mechanism that sends HTTP POST requests can call this route, for example a Dynamic Execution Engine (DEE) action or the REST client driver of Connect IoT. Send the requests with the `Content-Type: application/json` header.

The calling user must be authenticated and needs write permission on the path `data/cm-mes/events`. For more information, see [HTTP Server Permissions](/2-4-2/connectors/servers/http-server.md#permissions).

## Verifying the Integration

1. Install the service and set the parameters with the values of your MES instance.
2. Check that the connection is in the **Connected** state on the service details page in the Admin UI.
3. Check that the polled object data arrives on `enterprise/mes/object-info`, for example with the [Data Explorer](/2-4-2/monitoring/data-explorer.md). If the object does not exist in the MES, the response contains an error message from the MES instead of the object data.
4. Publish a test message to `enterprise/hamburg/assembly/line-1/press-01/data-collection` with a payload that matches your MES schema, and check in the MES UI that the data collection points have been posted.
5. The result of every HTTP request is published to the `/res` topic of the endpoint. Use the Data Explorer to inspect it. If the MES rejects a request, the message on the `/res` topic contains an `error` property with the HTTP status. A `401` status indicates wrong credentials, a `403` status indicates missing roles for the MES user.

## Service Commissioning File Example

{% file src="/files/TnDxxsLERvoF7WrkXvAI" %}

{% code title="critical-manufacturing-mes-example.yml" lineNumbers="true" expandable="true" %}

```yaml
---
# ----------------------------------------------------------------------------
# Service Commissioning File
# ----------------------------------------------------------------------------
# Copyright: Cybus GmbH
# Contact: support@cybus.io
# ----------------------------------------------------------------------------
# Critical Manufacturing MES Integration (Example)
# ----------------------------------------------------------------------------

description: >
  Service commissioning file for the bidirectional integration between
  Connectware and Critical Manufacturing MES (Example)

metadata:
  name: Critical Manufacturing MES Integration
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  mesHost:
    description: Hostname of your Critical Manufacturing MES instance
    type: string
    default: mes.example.com

  mesTenant:
    description: Tenant name configured on your MES environment
    type: string
    default: ExampleTenant

  oauthClientId:
    description: Client ID registered in the Security Portal
    type: string

  oauthClientSecret:
    description: Client secret registered in the Security Portal
    type: string

  mesObjectType:
    description: Object type of the MES business object to poll
    type: string
    default: Material

  mesObjectName:
    description: Name of the MES business object to poll
    type: string
    default: LOT-0001

  pollInterval:
    description: Polling interval for MES object data in milliseconds
    type: integer
    default: 60000

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise

resources:
  # Connection to the MES REST API, authenticated with the Security Portal
  # OAuth 2.0 client credentials flow
  mesConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: !ref mesHost
        port: 443
        oauthClientCredentials:
          auth_url: !sub 'https://${mesHost}/SecurityPortal/api/tenant/${mesTenant}/oauth2/token'
          client_id: !ref oauthClientId
          client_secret: !ref oauthClientSecret

  # Posts data collection points to the MES, one request per message
  dataCollectionEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref mesConnection
      write:
        path: /api/DataCollection/PostDataCollectionPoints

  dataCollectionMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/data-collection'
          publish:
            endpoint: !ref dataCollectionEndpoint
          rules:
            - transform:
                expression: '{ "body": $ }'

  # Polls one MES business object at a regular interval
  objectInfoEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref mesConnection
      subscribe:
        path: /api/GenericService/GetObjectByName
        interval: !ref pollInterval
        query:
          Type: !ref mesObjectType
          Name: !ref mesObjectName

  objectInfoMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref objectInfoEndpoint
          publish:
            topic: !sub '${topicRoot}/mes/object-info'

  # Calls any MES REST operation on demand. The message provides the
  # operation path in "pathAppend" and the input object in "body".
  mesRequestEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref mesConnection
      write:
        path: /api

  mesRequestMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/mes/request'
          publish:
            endpoint: !ref mesRequestEndpoint

  # HTTP route that MES workflows can call to send data to the shop floor
  mesEventServer:
    type: Cybus::Server::Http
    properties:
      basePath: /cm-mes

  mesEventRoute:
    type: Cybus::Node::Http
    properties:
      parent: !ref mesEventServer
      method: POST
      route: /events

  mesEventMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref mesEventRoute
          publish:
            topic: !sub '${topicRoot}/cm-mes/events'
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.cybus.io/2-4-2/guides/system-connectivity/mes-erp-business-systems/critical-manufacturing-mes-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
