> 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/cloud-iot-platforms/cumulocity-iot-integration.md).

# Cumulocity IoT Integration

This guide describes how to integrate Cumulocity IoT with Connectware. You configure a service commissioning file that sends shop floor data to Cumulocity IoT as device measurements over MQTT, using SmartREST static templates, and receives operations from Cumulocity IoT in return. A complete example file is available at the end of this guide.

## Objectives

* Creating device credentials for Connectware in Cumulocity IoT.
* Establishing an MQTT connection between Connectware and Cumulocity IoT.
* Registering a device and sending measurements using SmartREST static templates.
* Receiving operations and error messages from Cumulocity IoT in Connectware.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* Access to a Cumulocity IoT tenant, including the tenant domain (for example, `mytenant.cumulocity.com`), the tenant ID, and a user with permission to register devices in the Device management application.
* 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)).
* It helps to be familiar with [Connecting an MQTT Client to Publish and Subscribe Data](/2-4-2/guides/machine-connectivity/gateways-generic-protocols/connecting-an-mqtt-client-to-publish-and-subscribe-data.md).

## Connectware and Cumulocity IoT Integration

Cumulocity IoT integrates devices over its Core MQTT endpoint, using [SmartREST](https://cumulocity.com/docs/smartrest/smartrest-introduction/) as the payload format. SmartREST replaces JSON with comma-separated values (CSV). Each message is one CSV line that starts with a template ID, followed by the template fields. The [static templates](https://cumulocity.com/docs/smartrest/mqtt-static-templates/) cover the most common device operations, such as creating a device or sending a measurement, without any template setup on the Cumulocity IoT side.

Connectware communicates with Cumulocity IoT through the [MQTT connector](/2-4-2/connectors/enterprise-connectors/mqtt.md). The integration uses the following Cumulocity IoT topics:

| Topic  | Direction                 | Purpose                                                                |
| ------ | ------------------------- | ---------------------------------------------------------------------- |
| `s/us` | Connectware to Cumulocity | Publishing static templates, such as device creation and measurements. |
| `s/ds` | Cumulocity to Connectware | Receiving operations for the device.                                   |
| `s/e`  | Cumulocity to Connectware | Receiving error and debug messages for rejected publishes.             |

Cumulocity IoT identifies the device by the MQTT client ID of the connection. One MQTT connection represents one device. The MQTT topics on the Connectware side follow an ISA-95-style equipment hierarchy (`<enterprise>/<site>/<area>/<line>/<cell>`). The measurement mappings subscribe with wildcards across all levels, so any machine in the hierarchy is picked up without changing the integration.

{% hint style="info" %}
If you want each machine to appear as its own device in Cumulocity IoT, use the static templates for child devices (template `101` and the `s/us/<childId>` topics). For more information, refer to the [Cumulocity IoT static templates documentation](https://cumulocity.com/docs/smartrest/mqtt-static-templates/).
{% endhint %}

### Creating Device Credentials

Cumulocity IoT authenticates MQTT devices with device credentials. The MQTT username must have the format `<tenantID>/<username>`.

The standard single-device registration in Cumulocity IoT uses an interactive bootstrap handshake: the device connects with the shared `devicebootstrap` credentials and polls for its credentials until an administrator accepts the registration request. The Connectware MQTT connector does not implement this handshake. Instead, create the device credentials directly:

1. In the Cumulocity IoT Device management application, go to **Devices** > **Registration**.
2. Register the device using bulk device registration with a CSV file that contains the device ID and a password. Cumulocity IoT creates the device credentials immediately, with the username `device_<id>`. For more information, refer to [Registering devices](https://cumulocity.com/docs/device-management-application/registering-devices/) in the Cumulocity IoT documentation.

Alternatively, you can connect with the credentials of a dedicated Cumulocity IoT user that has the permissions of the built-in **Device** role.

### Cumulocity IoT Connection Properties

The connection to Cumulocity IoT requires the tenant and device credential values from the previous step. 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.

* `tenantDomain`: The domain of your Cumulocity IoT tenant, without the scheme. For example, `mytenant.cumulocity.com`.
* `tenantId`: The ID of your Cumulocity IoT tenant. For example, `t76543210`.
* `deviceUsername` and `devicePassword`: The device credentials. For credentials created through bulk device registration, the username is `device_<id>`.
* `deviceId`: The device identifier, used as the MQTT client ID. Cumulocity IoT links all messages of this connection to the device with this ID. The device ID must not contain colons.
* `topicRoot`: The root of the MQTT topic hierarchy on the Connectware side. Defaults to `enterprise`.

{% code lineNumbers="true" %}

```yaml
parameters:
  tenantDomain:
    description: Domain of your Cumulocity IoT tenant, without scheme
    type: string
    default: mytenant.cumulocity.com

  tenantId:
    description: ID of your Cumulocity IoT tenant
    type: string
    default: t76543210

  deviceUsername:
    description: Username of the device credentials, without the tenant ID prefix
    type: string
    default: device_press-01

  devicePassword:
    description: Password of the device credentials
    type: string

  deviceId:
    description: Device identifier, used as the MQTT client ID (no colons allowed)
    type: string
    default: press-01

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

{% endcode %}

### Cumulocity IoT Connection

To connect to Cumulocity IoT, we set up a `Cybus::Connection` resource that uses the MQTT connector. Cumulocity IoT accepts TLS-encrypted MQTT connections on port 8883 and supports MQTT 3.1.1. The username is composed of the tenant ID and the device username, joined with a slash.

{% code lineNumbers="true" %}

```yaml
resources:
  cumulocityConnection:
    type: Cybus::Connection
    properties:
      protocol: Mqtt
      connection:
        host: !ref tenantDomain
        port: 8883
        scheme: mqtts
        username: !sub '${tenantId}/${deviceUsername}'
        password: !ref devicePassword
        clientId: !ref deviceId
        keepalive: 60
```

{% endcode %}

If the Connectware host system does not have access to root CAs, add the root certificate of your Cumulocity IoT instance to the connection using the [caCert property](/2-4-2/connectors/enterprise-connectors/mqtt/mqttconnection.md#cacert-string).

### Sending SmartREST Messages to Cumulocity IoT

All static templates are published to the same Cumulocity IoT topic, `s/us`. We define one write endpoint for this topic and a mapping that forwards messages from a Connectware topic to it. The mapping has no rules, so Connectware forwards the payload unmodified (see [Input Format on Write](/2-4-2/connectors/enterprise-connectors/mqtt.md#input-format-on-write)).

{% code lineNumbers="true" %}

```yaml
upstreamEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Mqtt
    connection: !ref cumulocityConnection
    write:
      topic: s/us

upstreamMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/cumulocity/upstream'
        publish:
          endpoint: !ref upstreamEndpoint
```

{% endcode %}

This gives you a direct channel for any static template. To register the device in Cumulocity IoT, publish the device creation template `100` once to the Connectware topic `enterprise/cumulocity/upstream`:

{% code lineNumbers="true" %}

```
100,Press 01,c8y_MQTTDevice
```

{% endcode %}

Cumulocity IoT creates a device named `Press 01` and links it to the client ID of the connection. If a device for this client ID already exists, the message has no effect, so it is safe to send it again.

### Mapping Measurements to Static Templates

SmartREST messages are plain CSV strings, not JSON. Shop floor data in Connectware is typically JSON, so we use a [transform](/2-4-2/data-flows/rule-engine/data-processing-rules.md#transform) rule to build the CSV line with JSONata string concatenation. When the JSONata expression evaluates to a plain string, Connectware publishes the raw string without JSON encoding, which is exactly what the SmartREST endpoint expects. If the expression returned a number or an object instead, Connectware would publish it JSON-encoded and Cumulocity IoT would report an error on the `s/e` topic.

Temperature measurements have their own static template, `211`. The following mapping accepts messages like `{ "value": 22.5 }` from any machine in the topic hierarchy and turns them into the CSV line `211,22.5`. Cumulocity IoT adds the timestamp on the server side.

{% code lineNumbers="true" %}

```yaml
temperatureMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/temperature'
        publish:
          endpoint: !ref upstreamEndpoint
        rules:
          - transform:
              expression: '"211," & $string(value)'
```

{% endcode %}

For any other measurement, use the generic measurement template `200`, which takes the fragment, the series, the value, and optionally the unit. The following mapping builds the CSV line from a self-describing JSON payload:

{% code lineNumbers="true" %}

```yaml
measurementMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/measurement'
        publish:
          endpoint: !ref upstreamEndpoint
        rules:
          - transform:
              expression: '"200," & fragment & "," & series & "," & $string(value) & "," & unit'
```

{% endcode %}

A machine publishes its data as JSON, for example to `enterprise/hamburg/assembly/line-1/press-01/measurement`:

{% code lineNumbers="true" %}

```json
{
  "fragment": "PressureMeasurement",
  "series": "P",
  "value": 4.2,
  "unit": "bar"
}
```

{% endcode %}

Connectware transforms this message into `200,PressureMeasurement,P,4.2,bar` and publishes it to `s/us`. In Cumulocity IoT, the value appears as a measurement of the fragment `PressureMeasurement` and the series `P` on the device.

### Receiving Operations from Cumulocity IoT

Cumulocity IoT sends operations, such as a restart request, to the device on the `s/ds` topic. We define a subscribe endpoint for this topic and a mapping that publishes every operation to a Connectware topic, where any other Connectware service can pick it up. The messages are passed through unmodified and arrive as CSV lines, for example `510,press-01` for a restart operation.

{% code lineNumbers="true" %}

```yaml
operationsEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Mqtt
    connection: !ref cumulocityConnection
    subscribe:
      topic: s/ds

operationsMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref operationsEndpoint
        publish:
          topic: !sub '${topicRoot}/cumulocity/operations'
```

{% endcode %}

To update the status of an operation, publish the corresponding static template to the upstream topic: `501,c8y_Restart` sets the oldest pending restart operation to executing, `503,c8y_Restart` sets it to successful, and `502,c8y_Restart,<reason>` sets it to failed.

### Monitoring SmartREST Errors

Cumulocity IoT reports rejected publishes on the `s/e` topic, for example when a CSV line does not match any template. Subscribing to this topic makes the integration much easier to debug. The following endpoint and mapping forward all error messages to a Connectware topic:

{% code lineNumbers="true" %}

```yaml
errorEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Mqtt
    connection: !ref cumulocityConnection
    subscribe:
      topic: s/e

errorMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref errorEndpoint
        publish:
          topic: !sub '${topicRoot}/cumulocity/errors'
```

{% endcode %}

## Verifying the Integration

1. Install the service and set the parameters with your tenant and device credential values.
2. Check that the connection is in the **Connected** state on the service details page in the Admin UI. If the credentials are wrong, the connection does not reach the connected state.
3. Publish `100,Press 01,c8y_MQTTDevice` to the `enterprise/cumulocity/upstream` topic, for example with an MQTT client or the Admin UI. In the Cumulocity IoT Device management application, check that the device `Press 01` appears under **Devices** > **All devices**.
4. Publish a test message, for example `{ "value": 22.5 }`, to `enterprise/hamburg/assembly/line-1/press-01/temperature`. On the device page in Cumulocity IoT, open the **Measurements** tab and check that the temperature value appears.
5. Use the [Data Explorer](/2-4-2/monitoring/data-explorer.md) to inspect the `enterprise/cumulocity/errors` topic. If Cumulocity IoT rejects a message, the error message on this topic tells you why.
6. To test the return direction, create a restart operation for the device in Cumulocity IoT and check that a CSV line arrives on the `enterprise/cumulocity/operations` topic.

## Service Commissioning File Example

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

{% code title="cumulocity-iot-example.yml" lineNumbers="true" expandable="true" %}

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

description: >
  Service commissioning file for the integration between Connectware and
  Cumulocity IoT using SmartREST static templates over MQTT (Example)

metadata:
  name: Cumulocity IoT Integration
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  tenantDomain:
    description: Domain of your Cumulocity IoT tenant, without scheme
    type: string
    default: mytenant.cumulocity.com

  tenantId:
    description: ID of your Cumulocity IoT tenant
    type: string
    default: t76543210

  deviceUsername:
    description: Username of the device credentials, without the tenant ID prefix
    type: string
    default: device_press-01

  devicePassword:
    description: Password of the device credentials
    type: string

  deviceId:
    description: Device identifier, used as the MQTT client ID (no colons allowed)
    type: string
    default: press-01

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

resources:
  # Connection to the Cumulocity IoT Core MQTT endpoint
  cumulocityConnection:
    type: Cybus::Connection
    properties:
      protocol: Mqtt
      connection:
        host: !ref tenantDomain
        port: 8883
        scheme: mqtts
        username: !sub '${tenantId}/${deviceUsername}'
        password: !ref devicePassword
        clientId: !ref deviceId
        keepalive: 60

  # Publishes SmartREST static templates to Cumulocity IoT
  upstreamEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Mqtt
      connection: !ref cumulocityConnection
      write:
        topic: s/us

  # Direct channel for any static template, for example device creation (100)
  upstreamMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/cumulocity/upstream'
          publish:
            endpoint: !ref upstreamEndpoint

  # Sends temperature values as temperature measurements (template 211)
  temperatureMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/temperature'
          publish:
            endpoint: !ref upstreamEndpoint
          rules:
            - transform:
                expression: '"211," & $string(value)'

  # Sends self-describing JSON payloads as measurements (template 200)
  measurementMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/measurement'
          publish:
            endpoint: !ref upstreamEndpoint
          rules:
            - transform:
                expression: '"200," & fragment & "," & series & "," & $string(value) & "," & unit'

  # Receives operations from Cumulocity IoT
  operationsEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Mqtt
      connection: !ref cumulocityConnection
      subscribe:
        topic: s/ds

  operationsMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref operationsEndpoint
          publish:
            topic: !sub '${topicRoot}/cumulocity/operations'

  # Receives SmartREST error messages from Cumulocity IoT
  errorEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Mqtt
      connection: !ref cumulocityConnection
      subscribe:
        topic: s/e

  errorMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref errorEndpoint
          publish:
            topic: !sub '${topicRoot}/cumulocity/errors'
```

{% 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/cloud-iot-platforms/cumulocity-iot-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.
