Skip to main content
Version: 1.4.1

Cumulocity Mapper

The Cumulocity mapper, referred to as c8y-mapper in the rest of this document, maps data in thin-edge.io format into their equivalent Cumulocity format.

Registration​

Cumulocity keeps the record of all the registered devices and their associated metadata in its inventory. The c8y-mapper creates and maintains inventory entries for all the devices and services registered with thin-edge.io. The mapper subscribes to the following topics to get a list of all registered devices and services:

mosquitto_sub -t 'te/+' -t 'te/+/+' -t 'te/+/+/+' -t 'te/+/+/+/+'

The registration messages received for child devices and services are mapped as follows:

Child device​

thin-edge.io (input)

Topic
te/device/child01//
Payload
{
"@type": "child-device",
"name": "child01",
"type": "SmartHomeHub"
}

Cumulocity IoT (output)

Topic
c8y/s/us
Payload
101,<main-device-id>:device:child01,child01,SmartHomeHub

Where the <main-device-id> is added as the prefix to the external id to avoid id clashes with devices using the same name in other tedge deployments connected to the same tenant.

Child device with explicit id​

thin-edge.io (input)

Topic
te/device/child01//
Payload
{
"@type": "child-device",
"@id": "child01",
"name": "child01",
"type": "SmartHomeHub"
}

Cumulocity IoT (output)

Topic
c8y/s/us
Payload
101,child01,child01,SmartHomeHub

Where the provided @id is directly used as the external id.

Nested child device​

thin-edge.io (input)

Topic
te/device/nested_child01//
Payload
{
"@type": "child-device",
"@parent": "device/child01//",
"name": "nested_child01",
"type": "BatterySensor"
}

Cumulocity IoT (output)

Topic
c8y/s/us/<main-device-id>:device:child01
Payload
101,<main-device-id>:device:nested_child01,nested_child01,BatterySensor

Main device service​

thin-edge.io (input)

Topic
te/device/main/service/nodered
Payload
{
"@type": "service",
"name": "Node-Red",
"type": "systemd"
}

Cumulocity IoT (output)

Topic
c8y/s/us
Payload
102,<main-device-id>:device:main:service:nodered,systemd,Node-Red,up

Child device service​

thin-edge.io (input)

Topic
te/device/child01/service/nodered
Payload
{
"@type": "service",
"name": "Node-Red",
"type": "systemd"
}

Cumulocity IoT (output)

Topic
c8y/s/us/<main-device-id>:device:child01
Payload
102,<main-device-id>:device:child01:service:nodered,systemd,Node-Red,up

Where the unique external IDs to be used in the cloud are derived from the entity identifier subtopics, replacing the / characters with :.

note

The main device is registered with the cloud via the tedge connect c8y command execution and hence there is no mapping done for main device registration messages. Inventory data updates for the main device are handled differently.

Auto Registration of an entity​

Before any data messages from an entity can be processed, the entity has to be registered first. The entity can be registered either explicitly or implicitly (Auto registration).

With auto-registration, an entity does not need to explicitly send a registration message, and the registration is done automatically by the mapper on receipt of the first message from that entity. But, auto-registration is allowed only when the entity follows the default topic scheme: te/device/<device-id>/service/<service-id>.

For example, sending a measurement message to te/device/child1///m/temperature will result in the auto-registration of the device entity with topic id: device/child1// and the auto-generated external id: <main-device-id>:device:child1, derived from the topic id. Similarly, a measurement message on te/device/child1/service/my-service/m/temperature results in the auto-registration of both the device entity: device/child1// and the service entity: device/child1/service/my-service with their respective auto-generated external IDs, in that order.

Pros:

  • No need to have a separate registration message for an entity. This would be ideal for simple devices where programming an additional registration logic is not possible ( e.g: simple sensors that can only generate telemetry messages).

Cons:

  • Auto-registration of all entities is not possible in complex deployments with nested/hierarchical devices, as the parent of a nested child device can't be identified solely from its topic id (e.g: te/device/nested-child//). The parent information must be provided explicitly using a registration message so that any nested child devices are not wrongly auto-registered as immediate child devices of the main device.
  • Auto-registration results in the auto-generation of the device external id as well. If the user wants more control over it, then an explicit registration must be done.

Auto-registration can be enabled/disabled based on the complexity of the deployment. For simpler deployments with just a single level child devices, following the default topic scheme, auto-registration can be kept enabled. For any complex deployments requiring external id customizations or with nested child devices, auto-registration must be disabled.

Auto-registration can be disabled using the following tedge config command:

sudo tedge config set c8y.entity_store.auto_register false

Auto-registration is enabled, by default. When the auto registration is disabled, and if the device is not explicitly registered, then the c8y-mapper will ignore all the data messages received from that device, logging that error message on the te/errors topic indicating that the entity is not registered.

Telemetry​

Telemetry data types like measurements, events and alarms are mapped to their respective equivalents in Cumulocity as follows:

Measurement​

thin-edge.io (input)

Topic
te/device/main///m/environment
Payload
{
"temperature": 23.4
}

Cumulocity IoT (output)

Topic
c8y/measurement/measurements/create
Payload
{
"type": "environment",
"time": "2021-04-22T17:05:26.958340390+00:00",
"temperature": {
"temperature": {
"value": 23
}
}
}

Measurement without type​

thin-edge.io (input)

Topic
te/device/main///m/
Payload
{
"temperature": 23.4
}

Cumulocity IoT (output)

Topic
c8y/measurement/measurements/create
Payload
{
"type": "ThinEdgeMeasurement",
"time": "2021-04-22T17:05:26.958340390+00:00",
"temperature": {
"temperature": {
"value": 23
}
}
}

Measurement of child device​

thin-edge.io (input)

Topic
te/device/child01///m/
Payload
{
"temperature": 23.4
}

Cumulocity IoT (output)

Topic
c8y/measurement/measurements/create
Payload
{
"externalSource":{
"externalId":"<main-device-id>:device:child01",
"type":"c8y_Serial"
},
"type":"ThinEdgeMeasurement",
"time":"2013-06-22T17:03:14+02:00",
"temperature":{
"temperature":{
"value":23
}
}
}

Events​

thin-edge.io (input)

Topic
te/device/main///e/login_event
Payload
{
"text": "A user just logged in",
"time": "2021-01-01T05:30:45+00:00"
}

Cumulocity IoT (output)

Topic
c8y/s/us
Payload
400,login_event,"A user just logged in",2021-01-01T05:30:45+00:00

Event - Complex​

thin-edge.io (input)

Topic
te/device/main///e/login_event
Payload
{
"text": "A user just logged in",
"time": "2021-01-01T05:30:45+00:00",
"customFragment": {
"nested": {
"value": "extra info"
}
}
}

Cumulocity IoT (output)

Topic
c8y/event/events/create
Payload
{
"externalSource":{
"externalId":"<main-device-id>",
"type":"c8y_Serial"
},
"type":"login_event",
"text":"A user just logged in",
"time":"2021-01-01T05:30:45+00:00",
"customFragment": {
"nested": {
"value": "extra info"
}
}
}

Alarms​

thin-edge.io (input)

Topic
te/device/main///a/temperature_high
Payload
{
"severity": "critical",
"text": "Temperature is very high",
"time": "2021-01-01T05:30:45+00:00"
}

Cumulocity IoT (output)

Topic
c8y/s/us
Payload
301,temperature_high,"Temperature is very high",2021-01-01T05:30:45+00:00

Alarm - Complex​

thin-edge.io (input)

Topic
te/device/main///a/pressure_alarm
Payload
{
"severity": "major",
"time": "2023-01-25T18:41:14.776170774Z",
"text": "Pressure alarm",
"customFragment": {
"nested": {
"value": "extra info"
}
}
}

Cumulocity IoT (output)

Topic
c8y/alarm/alarms/create
Payload
{
"externalSource": {
"externalId": "<main-device-id>",
"type": "c8y_Serial"
},
"type": "pressure_alarm",
"severity": "MAJOR",
"time": "2023-01-25T18:41:14.776170774Z",
"text": "Pressure alarm",
"customFragment": {
"nested": {
"value": "extra info"
}
},
}

Health status​

thin-edge.io (input)

Topic
te/device/main/service/my-service/status/health
Payload
{
"status": "up",
"pid": 21037
}

Cumulocity IoT (output)

Topic
c8y/s/us/<service-external-id>
Payload
104,up

Twin​

The twin metadata is mapped to inventory data in Cumulocity.

Twin - Main device​

A device's digital twin model can be updated by publishing to a specific topic.

The type part of the topic is used to group the data so it is easier for components to subscribe to relevant parts.

thin-edge.io (input)

Topic (retain=true)
te/device/main///twin/device_OS
Payload
{
"family": "Debian",
"version": "11"
}

Cumulocity IoT (output)

Topic
c8y/inventory/managedObjects/update/<main-device-id>
Payload
{
"device_OS": {
"family": "Debian",
"version": "11"
}
}

Twin - Child Device​

thin-edge.io (input)

Topic (retain=true)
te/device/child01///twin/device_OS
Payload
{
"family": "Debian",
"version": "11"
}

Cumulocity IoT (output)

Topic
c8y/inventory/managedObjects/update/<main-device-id>:device:child01
Payload
{
"device_OS": {
"family": "Debian",
"version": "11"
}
}

Twin - Service on Main Device​

thin-edge.io (input)

Topic (retain=true)
te/device/main/service/tedge-agent/twin/runtime_stats
Payload
{
"memory": 3024,
"uptime": 86400
}

Cumulocity IoT (output)

Topic
c8y/inventory/managedObjects/update/<main-device-id>:device:main:service:tedge-agent
Payload
{
"runtime_stats": {
"memory": 3.3,
"uptime": 86400
}
}

Twin - Service on Child Device​

thin-edge.io (input)

Topic (retain=true)
te/device/child01/service/tedge-agent/twin/runtime_stats
Payload
{
"memory": 3.3,
"uptime": 86400
}

Cumulocity IoT (output)

Topic
c8y/inventory/managedObjects/update/<main-device-id>:device:child01:service:tedge-agent
Payload
{
"runtime_stats": {
"memory": 3.3,
"uptime": 86400
}
}

Twin data - Root fragments​

Data can be added on the root level of the twin by publishing the values directly to the topic with the key used as type. The payload can be any valid JSON value other than a JSON object. JSON objects must be published to their typed topics directly.

thin-edge.io (input)

Topic (retain=true)
te/device/main///twin/subtype
Payload
"my-custom-type"

Cumulocity IoT (output)

Topic
c8y/inventory/managedObjects/update/<main-device-id>
Payload
{
"subtype": "my-custom-type"
}
warning

Updating the following properties via the twin channel is not supported

  • name
  • type

as they are included in the entity registration message and can only be updated with another registration message.

Twin - Deleting a fragment​

thin-edge.io (input)

Topic (retain=true)
te/device/child01/service/tedge-agent/twin/runtime_stats
Payload
<<empty>>

Cumulocity IoT (output)

Topic
c8y/inventory/managedObjects/update/<main-device-id>:device:child01:service:tedge-agent
Payload
{
"runtime_stats": null
}

Base inventory model​

The contents of {tedge_config_dir}/device/inventory.json are used to populate the initial inventory fragments of the the main thin-edge.io device in Cumulocity. For example, if the inventory.json contains the following fragments:

inventory.json
{
"c8y_Firmware": {
"name": "raspberrypi-bootloader",
"version": "1.20140107-1",
"url": "31aab9856861b1a587e2094690c2f6e272712cb1"
},
"c8y_Hardware": {
"model": "BCM2708",
"revision": "000e",
"serialNumber": "00000000e2f5ad4d"
}
}

It is mapped to the following Cumulocity message:

Topic
c8y/inventory/managedObjects/update
Payload
{
"c8y_Agent": {
"name": "thin-edge.io",
"url": "https://thin-edge.io",
"version": "x.x.x"
},
"c8y_Firmware": {
"name": "raspberrypi-bootloader",
"version": "1.20140107-1",
"url": "31aab9856861b1a587e2094690c2f6e272712cb1"
},
"c8y_Hardware": {
"model": "BCM2708",
"revision": "000e",
"serialNumber": "00000000e2f5ad4d"
}
}

Where the c8y_Agent fragment is auto-generated by thin-edge.io and appended to the contents of the file before it is published.

The fragments in this file are also published to the te/device/main///twin/<fragment-key> topics so that the local twin metadata on the broker is also up-to-date and other components can also consume it. For example, the above inventory.json would result in the following twin messages:

Topic
te/device/main///twin/c8y_Agent
Payload
{
"name": "thin-edge.io",
"url": "https://thin-edge.io",
"version": "x.x.x"
}
Topic
te/device/main///twin/c8y_Firmware
Payload
{
"name": "raspberrypi-bootloader",
"version": "1.20140107-1",
"url": "31aab9856861b1a587e2094690c2f6e272712cb1"
}
Topic
te/device/main///twin/c8y_Hardware
Payload
{
"model": "BCM2708",
"revision": "000e",
"serialNumber": "00000000e2f5ad4d"
}
warning

The following keys in the inventory.json file are also ignored:

  • name
  • type

as they are included in the entity registration message and can only be updated with another registration message.

Updating entity type in inventory​

After updating the inventory with inventory.json file contents, the device type of the main device, set using the device.type tedge config key, is also updated in the inventory with the following message:

Topic
c8y/inventory/managedObjects/update
Payload
{
"type": "configured-device-type"
}

Operations/Commands​

Operations from Cumulocity are mapped to their equivalent commands in thin-edge.io format.

Supported Operations/Capabilities​

All the supported operations of all registered devices can be derived from the metadata messages linked to their respective cmd topics with a simple subscription as follows:

mosquitto_sub -v -t 'te/+/+/+/+/cmd/+'

If that subscription returns the following messages:

Output
[te/device/main///cmd/restart] {}
[te/device/main///cmd/log_upload] { "types": ["tedge-agent", "mosquitto"] }
[te/device/child01///cmd/config_snapshot] { "types": ["mosquitto", "tedge", "collectd"] }
[te/device/child01///cmd/config_update] { "types": ["mosquitto", "tedge", "collectd"] }

The cmd metadata registered for both the main device and the child device child01 are mapped to the following supported operations messages:

[c8y/s/us] 114,c8y_Restart,c8y_LogfileRequest
[c8y/s/us/<main-device-id>:device:child01] 114,c8y_UploadConfigFile,c8y_DownloadConfigFile

The operation specific metadata like types for log_upload, config_snapshot and config_update are also mapped to their corresponding supported logs and supported configs messages as follows:

[c8y/s/us] 118,"tedge-agent", "mosquitto"
[c8y/s/us/<main-device-id>:device:child01] 119,"mosquitto", "tedge", "collectd"

Device Restart​

Request​

Cumulocity IoT (input)

Topic
c8y/s/ds
Payload
510,<main-device-id>

thin-edge.io (output)

Topic
te/device/main///cmd/restart/<cmd-id>
Payload
{
"status": "init"
}

Response​

Even though operations on tedge can have different kinds of status for each operation type, the mapper recognizes and maps only the following status values as follows:

thin-edge.io (input)Cumulocity IoT (output)
Topic
te/device/main///cmd/restart/<cmd-id>
Payload
{
"status": "executing"
}
Topic
c8y/s/us
Payload
501,c8y_Restart
Topic
te/device/main///cmd/restart/<cmd-id>
Payload
{
"status": "successful"
}
Topic
c8y/s/us
Payload
503,c8y_Restart
Topic
te/device/main///cmd/restart/<cmd-id>
Payload
{
"status": "failed"
}
Topic
c8y/s/us
Payload
502,c8y_Restart

All other status values are just ignored.

Restart: Child device​

Cumulocity IoT (input)

Topic
c8y/s/ds
Payload
510,<main-device-id>:device:child01

thin-edge.io (output)

Topic
te/device/child01///cmd/restart
Payload
{}

Software Update​

Cumulocity IoT (input)

Topic
c8y/s/ds
Payload
528,<main-device-id>,nodered::debian,1.0.0,<c8y-url>,install,collectd,5.7,,install,rolldice,1.16,,delete

thin-edge.io (output)

Topic
te/device/main///cmd/software_update/<cmd_id>
Payload
{
"status": "init",
"updateList": [
{
"type": "debian",
"modules": [
{
"name": "nodered",
"version": "1.0.0",
"url": "<tedge-url>",
"action": "install"
},
{
"name": "collectd",
"version": "5.7",
"action": "install"
},
{
"name": "rolldice",
"version": "1.16",
"action": "remove"
}
]
}
]
}

Where the collectd binary from the <c8y-url> is downloaded to the tedge file transfer repository by the mapper, and the local <tedge-url> of that binary is included in the mapped request.

Configuration Snapshot​

Cumulocity IoT (input)

Topic
c8y/s/ds
Payload
526,<main-device-id>,collectd

thin-edge.io (output)

Topic
te/device/main///cmd/config_snapshot/<cmd_id>
Payload
{
"status": "init",
"type": "collectd",
"url": "<tedge-url>"
}

Where the url is the target URL in the tedge file transfer repository to which the config snapshot must be uploaded.

Configuration Update​

Cumulocity IoT (input)

Topic
c8y/s/ds
Payload
524,<main-device-id>,<c8y-url>,collectd

thin-edge.io (output)

Topic
te/device/main///cmd/config_update/<cmd_id>
Payload
{
"status": "init",
"type": "collectd",
"url": "<tedge-url>"
}

Where the collectd configuration binary from the <c8y-url> is downloaded to the tedge file transfer repository by the mapper, and the local <tedge-url> of that binary is included in the mapped request.

Log Upload​

Cumulocity IoT (input)

Topic
c8y/s/ds
Payload
522,<main-device-id>,tedge-agent,2013-06-22T17:03:14.000+02:00,2013-06-22T18:03:14.000+02:00,ERROR,1000

thin-edge.io (output)

Topic
te/device/main///cmd/log_upload/<cmd_id>
Payload
{
"status": "init",
"type": "tedge-agent",
"tedgeUrl": "<tedge-url>",
"dateFrom": "2013-06-22T17:03:14.000+02:00",
"dateTo": "2013-06-23T18:03:14.000+02:00",
"searchText": "ERROR",
"lines": 1000
}

Where the url is the target URL in the tedge file transfer repository to which the config snapshot must be uploaded.