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)
te/device/child01//
{
"@type": "child-device",
"name": "child01",
"type": "SmartHomeHub"
}
Cumulocity IoT (output)
c8y/s/us
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)
te/device/child01//
{
"@type": "child-device",
"@id": "child01",
"name": "child01",
"type": "SmartHomeHub"
}
Cumulocity IoT (output)
c8y/s/us
101,child01,child01,SmartHomeHub
Where the provided @id
is directly used as the external id.
Nested child device​
thin-edge.io (input)
te/device/nested_child01//
{
"@type": "child-device",
"@parent": "device/child01//",
"name": "nested_child01",
"type": "BatterySensor"
}
Cumulocity IoT (output)
c8y/s/us/<main-device-id>:device:child01
101,<main-device-id>:device:nested_child01,nested_child01,BatterySensor
Main device service​
thin-edge.io (input)
te/device/main/service/nodered
{
"@type": "service",
"name": "Node-Red",
"type": "systemd"
}
Cumulocity IoT (output)
c8y/s/us
102,<main-device-id>:device:main:service:nodered,systemd,Node-Red,up
Child device service​
thin-edge.io (input)
te/device/child01/service/nodered
{
"@type": "service",
"name": "Node-Red",
"type": "systemd"
}
Cumulocity IoT (output)
c8y/s/us/<main-device-id>:device:child01
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 :
.
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)
te/device/main///m/environment
{
"temperature": 23.4
}
Cumulocity IoT (output)
c8y/measurement/measurements/create
{
"type": "environment",
"time": "2021-04-22T17:05:26.958340390+00:00",
"temperature": {
"temperature": {
"value": 23
}
}
}
Measurement without type​
thin-edge.io (input)
te/device/main///m/
{
"temperature": 23.4
}
Cumulocity IoT (output)
c8y/measurement/measurements/create
{
"type": "ThinEdgeMeasurement",
"time": "2021-04-22T17:05:26.958340390+00:00",
"temperature": {
"temperature": {
"value": 23
}
}
}
Measurement of child device​
thin-edge.io (input)
te/device/child01///m/
{
"temperature": 23.4
}
Cumulocity IoT (output)
c8y/measurement/measurements/create
{
"externalSource":{
"externalId":"<main-device-id>:device:child01",
"type":"c8y_Serial"
},
"type":"ThinEdgeMeasurement",
"time":"2013-06-22T17:03:14+02:00",
"temperature":{
"temperature":{
"value":23
}
}
}
Measurement with unit​
The unit is a metadata associated with measurements which can be registered as a metadata message for a given measurement type.
If the following metadata message is registered for the environment
measurement type:
- tedge
- mosquitto
- mqtt
tedge mqtt pub -r 'te/device/main///m/environment/meta' '{
"units": {
"temperature": "°C"
}
}'
mosquitto_pub -r -t 'te/device/main///m/environment/meta' -m '{
"units": {
"temperature": "°C"
}
}'
te/device/main///m/environment/meta
{
"units": {
"temperature": "°C"
}
}
Then subsequent messages will be mapped with the registered unit value as follows.
thin-edge.io (input)
te/device/main///m/environment
{
"temperature": 23.4
}
Cumulocity IoT (output)
c8y/measurement/measurements/create
{
"type": "environment",
"time": "2021-04-22T17:05:26.958340390+00:00",
"temperature": {
"temperature": {
"value": 23,
"unit": "°C"
}
}
}
Events​
thin-edge.io (input)
te/device/main///e/login_event
{
"text": "A user just logged in",
"time": "2021-01-01T05:30:45+00:00"
}
Cumulocity IoT (output)
c8y/s/us
400,login_event,"A user just logged in",2021-01-01T05:30:45+00:00
Event - Complex​
thin-edge.io (input)
te/device/main///e/login_event
{
"text": "A user just logged in",
"time": "2021-01-01T05:30:45+00:00",
"customFragment": {
"nested": {
"value": "extra info"
}
}
}
Cumulocity IoT (output)
c8y/event/events/create
{
"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)
te/device/main///a/temperature_high
{
"severity": "critical",
"text": "Temperature is very high",
"time": "2021-01-01T05:30:45+00:00"
}
Cumulocity IoT (output)
c8y/s/us
301,temperature_high,"Temperature is very high",2021-01-01T05:30:45+00:00
Alarm - Complex​
thin-edge.io (input)
te/device/main///a/pressure_alarm
{
"severity": "major",
"time": "2023-01-25T18:41:14.776170774Z",
"text": "Pressure alarm",
"customFragment": {
"nested": {
"value": "extra info"
}
}
}
Cumulocity IoT (output)
c8y/alarm/alarms/create
{
"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)
te/device/main/service/my-service/status/health
{
"status": "up",
"pid": 21037
}
Cumulocity IoT (output)
c8y/s/us/<service-external-id>
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)
te/device/main///twin/device_OS
{
"family": "Debian",
"version": "11"
}
Cumulocity IoT (output)
c8y/inventory/managedObjects/update/<main-device-id>
{
"device_OS": {
"family": "Debian",
"version": "11"
}
}
Twin - Child Device​
thin-edge.io (input)
te/device/child01///twin/device_OS
{
"family": "Debian",
"version": "11"
}
Cumulocity IoT (output)
c8y/inventory/managedObjects/update/<main-device-id>:device:child01
{
"device_OS": {
"family": "Debian",
"version": "11"
}
}
Twin - Service on Main Device​
thin-edge.io (input)
te/device/main/service/tedge-agent/twin/runtime_stats
{
"memory": 3024,
"uptime": 86400
}
Cumulocity IoT (output)
c8y/inventory/managedObjects/update/<main-device-id>:device:main:service:tedge-agent
{
"runtime_stats": {
"memory": 3.3,
"uptime": 86400
}
}
Twin - Service on Child Device​
thin-edge.io (input)
te/device/child01/service/tedge-agent/twin/runtime_stats
{
"memory": 3.3,
"uptime": 86400
}
Cumulocity IoT (output)
c8y/inventory/managedObjects/update/<main-device-id>:device:child01:service:tedge-agent
{
"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)
te/device/main///twin/subtype
"my-custom-type"
Cumulocity IoT (output)
c8y/inventory/managedObjects/update/<main-device-id>
{
"subtype": "my-custom-type"
}
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)
te/device/child01/service/tedge-agent/twin/runtime_stats
<<empty>>
Cumulocity IoT (output)
c8y/inventory/managedObjects/update/<main-device-id>:device:child01:service:tedge-agent
{
"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:
{
"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:
c8y/inventory/managedObjects/update
{
"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:
te/device/main///twin/c8y_Agent
{
"name": "thin-edge.io",
"url": "https://thin-edge.io",
"version": "x.x.x"
}
te/device/main///twin/c8y_Firmware
{
"name": "raspberrypi-bootloader",
"version": "1.20140107-1",
"url": "31aab9856861b1a587e2094690c2f6e272712cb1"
}
te/device/main///twin/c8y_Hardware
{
"model": "BCM2708",
"revision": "000e",
"serialNumber": "00000000e2f5ad4d"
}
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:
c8y/inventory/managedObjects/update
{
"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:
[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)
c8y/s/ds
510,<main-device-id>
thin-edge.io (output)
te/device/main///cmd/restart/<cmd-id>
{
"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
Payload
| Topic
Payload
|
Topic
Payload
| Topic
Payload
|
Topic
Payload
| Topic
Payload
|
All other status
values are just ignored.
Restart: Child device​
Cumulocity IoT (input)
c8y/s/ds
510,<main-device-id>:device:child01
thin-edge.io (output)
te/device/child01///cmd/restart
{}
Software Update​
Cumulocity IoT (input)
c8y/s/ds
528,<main-device-id>,nodered::debian,1.0.0,<c8y-url>,install,collectd,5.7,,install,rolldice,1.16,,delete
thin-edge.io (output)
te/device/main///cmd/software_update/<cmd_id>
{
"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)
c8y/s/ds
526,<main-device-id>,collectd
thin-edge.io (output)
te/device/main///cmd/config_snapshot/<cmd_id>
{
"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)
c8y/s/ds
524,<main-device-id>,<c8y-url>,collectd
thin-edge.io (output)
te/device/main///cmd/config_update/<cmd_id>
{
"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)
c8y/s/ds
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)
te/device/main///cmd/log_upload/<cmd_id>
{
"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.