Introduction
This section walks you through the SmartREST protocol, the data format used, as well as the anatomy and registration of SmartREST templates. Built-in messages as well as errors are also discussed. For a step-by-step description, see Using the REST interface in the Microservice SDK guide.
The Cumulocity IoT REST APIs provide you with a generic IoT protocol that is simple to use from most environments. It can be ad-hoc adapted to any IoT use case and it uses standard Internet communication and security mechanisms. While this is a great leap forward over tailored IoT protocols with proprietary technologies, it poses some challenges to very constrained environments such as low-end microcontrollers or low-bandwidth communication channels.
For these environments, Cumulocity IoT offers the so-called SmartREST protocol. SmartREST combines the benefits of standard technology and tailored protocols:
- It continues to work on any network by using standard HTTP technology.
- It supports HTTP authentication and encryption.
- It still gracefully handles protocol versioning.
- Its network traffic usage is close to custom-optimized protocols by transferring pure payload data during normal operation.
- It is based on CSV (comma-separated values), hence, it is easy to handle from C-based environments.
- It supports server-generated timestamps for devices without clocks.
In the next section, we will discuss the concepts behind SmartREST and the basic protocol that is used. SmartREST is based on separating metadata from payload data by using templates, which are described below. Finally, we show how to send and receive data using SmartREST.
How does SmartREST work?
The image below illustrates how SmartREST works. Devices and other clients connect to a dedicated SmartREST endpoint on Cumulocity IoT and send their data in rows of comma-separated values. These rows are expanded by Cumulocity IoT’s SmartREST proxy into standard Cumulocity IoT REST API requests. In the same way, responses from Cumulocity IoT are compressed by the proxy from their original JSON format into comma-separated values before sending them back to the device.
How can Cumulocity IoT interpret comma-separated values into meaningful REST requests?
For that purpose, devices register templates with Cumulocity IoT. The templates contain the expanded REST requests together with placeholders into which the Cumulocity IoT SmartREST proxy consecutively inserts the comma-separate values. For responses, the templates describe which values to pick from the structured REST response to construct comma-separated values.
Templates are associated with software or firmware versions of a device. Usually, a particular implementation of a device or application can only issue a particular set of well-defined types of requests. All devices with the same implementation share the same set of request types. Hence, the templates can be defined at implementation time. To make the templates available to Cumulocity IoT, the first device with a particular implementation will send its templates and makes them available for usage by all similar devices.
This process is illustrated in the image below. Assume that a device with an implementation version “Device_1.0” starts communicating through SmartREST. After retrieving its credentials, the device will ask the SmartREST proxy if its template is already known. If the template is not found on the server, the device will send its template in a single static text request to Cumulocity IoT. Once this procedure has been carried out, all similar devices using that template can start communicating using SmartREST without re-sending the template to the server.
The example also roughly illustrates the translation process. In “Template 1”, "%%"
is a placeholder to be filled by the SmartREST proxy. "time"
is filled with a server-side timestamp (see below). The remaining placeholders are filled with request data. The line 1,200,20.5
in the example request is interpreted as follows:
- The first column references the template to be used, in this case Template 1.
200
refers to the first free placeholder in the template, in this case the ID in the"source"
element (The ID of the device that sends the measurement).20.5
refers to the second free placeholder in the template, here the value of the temperature measurement.
The basic SmartREST protocol
The basic structure of all SmartREST requests is as follows:
- All requests are POST requests to the endpoint /s, regardless of what the requests finally translate to.
- The standard HTTP Basic Authorization header is used to authenticate the client.
- An additional “X-Id:” header is used to identify the implementation of the client, either as device type (such as “Device_1.0”) or as an identifier returned by the template registration process.
- A request body contains rows of text in comma-separated value format. Each row corresponds to one request to the standard Cumulocity IoT REST API.
- The response is always “200 OK”.
- The response body again contains rows of comma-separated values. A row corresponds to a response from the Cumulocity IoT REST API on a particular request.
Using the above example, a SmartREST request would be as follows:
POST /s HTTP/1.1
Authorization: <AUTHORIZATION>
X-Id: Device_1.0
1,200,20.5
And the corresponding response would be:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
20,0
To match the requests and responses, a response line contains – next to the error code – the line of the request that the response answers. In this example, 20
indicates “OK” and 0
refers to the first line of the request.
How are templates registered?
As described above, a client using SmartREST will first ask if its SmartREST templates are already known to the server. This is done with an empty SmartREST request:
POST /s HTTP/1.1
Authorization: <AUTHORIZATION>
X-Id: Device_1.0
If the device implementation is known, the response will return an ID that can be used as “shorthand” in the “X-Id” header of later requests.
HTTP/1.1 200 OK
20,<id>
If the device implementation is unknown, the response will be:
HTTP/1.1 200 OK
40,"No template for this X-ID"
In this case, create all templates used in your device implementation.
POST /s HTTP/1.1
Authorization: <AUTHORIZATION>
X-Id: Device_1.0
10,1,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,,%%,NOW UNSIGNED NUMBER,{ "time": "%%", "type": ... }
In this example, 10
refers to a request template (whereas “11” would refer to a response template). The template is number 1
, so SmartREST requests using this template have a “1” in their first column. The template refers to a POST
request to the endpoint /measurement/measurements with a content type of application/vnd.com.nsn.cumulocity.measurement+json
. The placeholder used in the template is %%
. The placeholders are a time stamp (NOW
), an unsigned number and a general number. Finally, the last column contains the body of the template to be filled in a POST request.
How are responses handled?
The above example illustrated the handling of requests and request templates. For responses, JSONPath expressions translate Cumulocity IoT REST responses into CSV. Assume, for example, that a device has a display and can show a message on it. An operation to update the message would look like:
{
"c8y_Message": {
"text": "Hello, world!"
},
"creationTime": "2019-02-25T08:32:45.435+01:00",
"deviceId": "8789602",
"status": "PENDING"
}
On the client side, the device mainly needs to know the text to be shown. In JSONPath, the "text"
property is extracted using the following syntax:
$.c8y_Message.text
In this syntax, $
refers to the root of the data structure and the dot (.
) selects an element from the data structure. For more details, refer to the JSONPath reference.
A device usually queries for all operations that are associated with it and that have a status of PENDING. The standard Cumulocity IoT response to such queries looks like:
{
"operations": [{
"c8y_Message": {
"text": "Hello, world!"
},
"creationTime": "2014-02-25T08:32:45.435+01:00",
"deviceId": "8789602",
"status": "PENDING"
}, {
"c8y_Relay": {
"status": "OPEN"
}
}]
}
The response contains a list of operations which can have different types. To work with such a structure, use the following response template:
11,2,$.operations,$.c8y_Message,$.c8y_Message.text
This means, value by value:
- 11: This is a response template.
- 2: It is the template number 2.
- $.operations: The response is a list and the list’s property is “operations”.
- $.c8y_Message: This template applies to responses with the property
c8y_Message
. - $.c8y_Message.text: The text will be extracted from the message and will be returned.
The SmartREST client will thus get the following response:
HTTP/1.1 200 OK
2,0,"Hello, world!"
That is, the response was created using template 2, the template to translate display message operations. The response refer to the first request sent. The actual message to set is “Hello, world!”.
MQTT quick reference
Quick reference
Connection
- CONNECT d:1234:myDevice_10 acme/device_1234
Connect the device with serial “1234” and default template myDevice_10 to tenant “acme” and user “device_1234”.
Topics
Publish
- PUBLISH s/us - Send a static template.
- PUBLISH s/us/5678 - Send a static template as child “5678”.
- PUBLISH s/ud - Send a message using the default template (myDevice_10).
- PUBLISH s/ud/5678 - Same as above, but as child “5678”.
- PUBLISH s/uc/myCommon_10 - Send a message using myCommon_10 template.
- PUBLISH s/uc/myCommon_10/5678 - Same as above, but as child “5678”.
Subscribe
- SUBSCRIBE s/ds - Receive static commands.
- SUBSCRIBE s/dd - Receive commands using the default template (myDevice_10).
- SUBSCRIBE s/dc/myCommon_10 - Receive commands using the myCommon_10 template.
- SUBSCRIBE s/e - Receive error messages.
Topic format
<protocol>/<direction><type>[/<template>][/<child_id>]
where:
<protocol>
can be s (persistent), t (transient), q (quiescent) and c (CEP), see SmartREST 1.0 > The protocol > Processing mode for more information.<direction>
can be u (upstream from the device), d (downstream to the device) or e (error).<type>
can be s (static), c (custom, device-defined), d (default), t (template) or cr (credentials).
Device registration
- CONNECT 1234 management/devicebootstrap
- SUBSCRIBE s/dcr
- PUBLISH s/ucr
- PUBLISH s/ucr
- …
- 70,tenant,username,password
Template registration
- PUBLISH s/ut/myCommon_10
- 10,999,POST,MEASUREMENT,,c8y_MyMeasurement;;c8y_MyMeasurement.M.value,NUMBER,… 10,msgId,api,method,response,type,time,custom1.path,custom1,type,custom1.value
Templates
See the templates quick reference for an overview of the available MQTT static templates.
SmartREST 2.0
This section describes the SmartREST 2.0 payload format that can be used with the Cumulocity IoT MQTT implementation.
SmartREST 2.0 was designed to make use of the MQTT protocol, so it may reduce the payload even more than the SmartREST 1.0 via HTTP.
SmartREST 2.0 is only available via MQTT and it offers the following MQTT topics for the main communication:
To publish messages:
s/uc/<X-ID>
To publish messages in transient mode:
t/uc/<X-ID>
To publish messages in quiescent mode:
q/uc/<X-ID>
To publish messages in CEP mode:
c/uc/<X-ID>
Refer to SmartREST 1.0 > The protocol > Processing mode in the Reference guide for more information about transient, quiescent & CEP data processing.
To subscribe for responses:
s/dc/<X-ID>
The topics for creating templates are described in Creating templates via MQTT.
Changes from SmartREST 1.0
In its base, SmartREST 2.0 is like the previous version: a CSV-like payload format that is backed by previously created templates to finally create the targeted JSON structure.
Several changes in the functionality have been made:
- Templates no longer contain IDs of objects (instead, IDs will be resolved by, for example, MQTT ClientId)
- Managed objects can be created and retrieved directly with external IDs
- Creating request templates now uses JSON path (like response templates)
- Support for lists in responses
- Responses also return if only part of the patterns were found
- Declaring a default X-ID for the connection
Supported templates
SmartREST 2.0 lets you create templates for the following matching HTTP methods:
API | GET | POST | PUT |
---|---|---|---|
Inventory | x | x | x |
Alarm | x | x | |
Event | x | ||
Measurement | x | ||
Operation | x |
Additionally, you can create templates to return certain values from responses and operations.
Template collections
A template collection is a set of request and response templates that specifies a device communication protocol. Each collection is referenced by a unique ID (called X-ID).
Creating templates via MQTT
Like in SmartREST 1.0, you must pass all templates in a collection in one message. After the creation of a template collection, it can no longer be modified through MQTT.
When creating templates, the client needs to publish to the following topic:
s/ut/<X-ID>
To verify if a template collection exists, the client can subscribe to the topic:
s/dt
When subscribed, the client can send an empty message to the creation topic which will trigger a new message about the creation status of this X-ID.
Examples
Empty publish to s/ut/myExistingTemplateCollection
20,myExistingTemplateCollection,<ID of collection>
Empty publish to s/ut/myNotExistingTemplateCollection
41,myNotExistingTemplateCollection
Request templates
A request template contains the following basic fields:
Field | Data type | Possible values | Mandatory | Description |
---|---|---|---|---|
messageId | String | Y | Unique ID to reference the template within the collection | |
method | String | GET PUT POST |
Y | Whether to get, update or create data |
api | String | INVENTORY MEASUREMENT ALARM EVENT OPERATION |
Y | Cumulocity IoT API to be used |
response | Boolean | true false |
N | Whether the request should trigger response templates. For GET templates by default true otherwise by default false |
mandatoryValues | List<String> | Y | Values for the mandatory fields on the API. The values depend on the API and method the template uses | |
customValues | List<CustomValue> | N | Custom values that should be added to the object |
A request template lists all the fragments in the object structure (mandatory and custom) that should be added when creating or updating the data. It can set fixed values in the template that will then be replaced by the server. If it does not set the value in the template, the value needs to be included in the publish message (this includes mandatoryValues).
Example
We create a template to create a measurement like this (measurements have two mandatory values: type and time)
# 10,msgId,method,api,response,type,time,custom1.path,custom1.type,custom1.value
10,999,POST,MEASUREMENT,,c8y_MyMeasurement,,c8y_MyMeasurement.M.value,NUMBER,
This template defines one additional custom property for the measurement. It leaves two fields empty in the template declaration (time and the custom property), so to use the template the client needs to send these two values:
999,2016-06-22T17:03:14.000+02:00,25
# We can also use server time by leaving the time empty
999,,25
The following sections will get into more detail of how to create and use different templates.
GET templates
GET templates for the inventory do not need any mandatory or custom values. Instead, they use two different fields.
With SmartREST 2.0 you have the option to either get an object from inventory by its ID or by an external ID directly. Therefore, instead of the fields mandatoryValues and customValues, the following two fields are used:
Field | Data type | Possible values | Mandatory | Description |
---|---|---|---|---|
byId | Boolean | true false |
Y | Whether the GET should be executed by Cumulocity IoT ID (=true) or externalId (=false) |
externalIdType | String | N | Sets a fixed externalIdType if the template calls by externalId |
This enables you to query inventory in three different ways:
By Cumulocity IoT ID
# Creation:
10,999,GET,INVENTORY,,true
# Usage:
999,123456
By external ID with a fixed type in the template
# Creation:
10,999,GET,INVENTORY,,false,c8y_Serial
# Usage:
999,myDeviceImei
By external ID without fixed type in the template
# Creation:
10,999,GET,INVENTORY,,false
# Usage:
999,c8y_Serial,myDeviceImei
POST templates
POST templates require a different set of mandatory values based on the API:
API | mandatory values |
---|---|
MEASUREMENT | type, time |
EVENT | type, text, time |
ALARM | type, text, status, severity, time |
INVENTORY | externalIdType |
This results in the following minimal template creations:
# Creation:
10,100,POST,MEASUREMENT,false,c8y_MyMeasurement,,c8y_MyMeasurement.M.value,NUMBER,
10,101,POST,EVENT,,c8y_CustomEvent,mytext,,
10,102,POST,ALARM,,c8y_CustomAlarm,mytext,ACTIVE,MAJOR,
# Usage:
100
101
102
Creating data on the inventory optionally includes the creation of an externalId for that object. This is controlled by the mandatory value externalIdType.
# Creation:
10,100,POST,INVENTORY,,c8y_MySerial
# Usage:
# Create object with externalId c8y_MySerial/myImei
100,myImei
# Create object with externalId c8y_MySerial/myImei
101,myImei,c8y_MySerial
# This message will result in not creating an external ID
101,,c8y_MySerial
PUT templates
PUT templates for inventory follow the same logic as the GET templates, and with the addition that you can also use custom values for PUT.
# Creation:
# 10,msgId,method,api,response,byId,externalIdTyoe,custom1.path,custom1.type,custom1.value
10,999,PUT,INVENTORY,,false,c8y_Serial,c8y_MyCustomValue,STRING,
# Usage:
999,myDeviceImei,myValue
The PUT template for alarms uses the type of the alarm to find the alarm to update. It will first check the ACTIVE alarms and, if there is no ACTIVE alarm, it will check the ACKNOWLEDGED alarms.
# Creation:
# 10,msgId,method,api,response,type,custom1.path,custom1.type,custom1.value
10,999,PUT,ALARM,,c8y_MyCustomAlarm,status,ALARMSTATUS
# Usage:
999,CLEARED
PUT templates for operations use the fragment of the operation to find the operation. It will first check the EXECUTING operations and, if there is no EXECUTING operation, it will check the PENDING operations.
# Creation:
# 10,msgId,method,api,response,fragment,custom1.path,custom1.type,custom1.value
10,999,PUT,OPERATION,,c8y_MyOperation,status,OPERATIONSTATUS,SUCCESSFUL,c8y_Fragment.val,NUMBER,
# Usage:
999,24
Adding custom properties
All POST and PUT values enable you to add custom properties to the results of the templates.
A single custom property requires you to add the following three values to your template creation:
Field | Description |
---|---|
path | A JsonPath for the value that should be set |
type | An optional data type of the value. Default: STRING |
value | The value to be set. Leaving this field empty requires the client to send the value when using the template |
Type | Description |
---|---|
STRING | The default type. No additional verification of the value |
DATE | A time stamp in the ISO 8601 format. Using date and not sending a time stamp results in the use of server time |
NUMBER | An integer or number with decimal places |
INTEGER | An integer |
UNSIGNED | An integer (only positive) |
FLAG | An empty map (for example c8y_IsDevice: {}). The client does not need to send anything for this value |
SEVERITY | A severity of an alarm. Used to update the severity field of alarms |
ALARMSTATUS | A status of an alarm. Used to update the status field of alarms |
OPERATIONSTATUS | A status of an operation. Used to update the status field of operations |
Examples
Template for clearing an alarm with an additional custom property
# Creation:
10,999,PUT,ALARM,,c8y_MyCustomALarm,status,ALARMSTATUS,CLEARED,c8y_CustomFragment.reason,STRING,
# Usage:
999,Device resolved alarm on its own
Template for creating a custom measurement
# Creation:
10,999,POST,MEASUREMENT,,c8y_CustomMeasurement,,c8y_CustomMeasurement.custom.value,NUMBER,,c8y_CustomMeasurement.custom.unit,STRING,X
# Usage:
999,30.6
Template for updating a property in the device
# Creation:
10,999,PUT,INVENTORY,,false,c8y_Serial,c8y_MyCustomValue,STRING,
# Usage:
999,myDeviceImei,updatedValue
Response templates
The SmartREST 2.0 response templates use the same structure as in SmartREST 1.0.
Field | Data type | Mandatory | Description |
---|---|---|---|
messageId | String | Y | Unique ID to reference the template within the collection |
base | String | N | A JsonPath prefix that all patterns will use |
condition | String | N | A JsonPath that needs to exist in the object to use the pattern |
pattern | List<String> | Y | A list of JsonPath that will be extracted from the object and returned to the device |
Response templates will be used for every operation and for any request template that defines the response field with true. In each case, the server will try every registered response template, so there might be multiple response lines for a single operation or request.
SmartREST 2.0 will always return a response template if the condition is true (or no condition was defined). Patterns that did not resolve will be returned as empty string.
You should make use of the condition field to control when response templates should be returned.
In the examples below, you can see how to query data and parse custom operations.
Querying data from the device object
Device object:
{
"id": "12345",
"type": "myMqttDevice",
"c8y_IsDevice": {},
"c8y_Configuration": "val1=1\nval2=2"
}
Template creation:
10,999,GET,INVENTORY,,true
11,888,,c8y_IsDevice,type,c8y_Test,c8y_Configuration
Client publishes:
999,12345
Client receives:
888,myMqttDevice,,"val1=1\nval2=2"
Parsing custom operations
Operation object:
{
"id": "12345",
"deviceId": "67890",
"agentId": "67890",
"status": "PENDING",
"c8y_CustomConfiguration": {
"val1": "1",
"val2": "2",
"customValues": ["a", "b", "c"]
},
"description": "Send custom configuration"
}
Template creation:
11,111,c8y_CustomConfiguration,deviceId,val1,val2,customValues[*]
11,222,,deviceId,c8y_CustomConfiguration.val1,c8y_CustomConfiguration.val2
11,333,,deviceId,val1,val2,customValues[*]
11,444,c8y_CustomConfiguration,c8y_CustomConfiguration.val3,val1,val2,customValues[*]
Client receives (assuming the ClientId is “myMqttTestDevice”):
111,myMqttTestDevice,1,2,a,b,c
222,myMqttTestDevice,1,2
333,myMqttTestDevice,,,
The template 444 is not returned as the condition does not match the operation.
Querying data from the device object containing key with multiple objects
Device object:
{
"id": "12345",
"name": "test",
"type": "c8y_MQTTdevice",
"c8y_IsDevice": {},
"myList": [
{
"pid": 12345,
"type": "test"
},
{
"pid": 123456,
"type": "test2"
}
]
}
Template creation:
10,999,GET,INVENTORY,,true
11,888,,,"$.myList[*].type"
Client publishes:
999,12345
Client receives:
888,test,test2
Using a default collection
Having the X-ID as part of the topic gives you the freedom to easily use multiple template collections, but adds additional bytes for every message. If anyway the device uses mostly (or completely) a single collection, it makes sense to specify this collection as your default collection.
With a default collection specified, the client can use special topics which do not require the X-ID, and instead the server will use the X-ID previously specified. The topics are s/ud for publishing and s/dd for subscribing.
You can specify one X-ID within your MQTT ClientId (see MQTT implementation).
Your MQTT ClientId could look like this:
d:myDeviceSerial:myDefaultTemplateXID
d:
at the beginning to specify that the client is a device.It is not required that the default template exists at the time of establishing the MQTT connection (it will be verified once the client uses it).
Handling of IDs
Concept of ID-less communication
The MQTT implementation of Cumulocity IoT is specifically designed for device communication. Therefore, it tries to remove as much unnecessary logic from the client side as possible.
Using the REST (or SmartREST) protocol requires to know the ID of every object, alarm and operation you want to update. Hence, a client needs to keep a state of these IDs. For example, if it creates an alarm, it needs to know the ID of the alarm so it can clear it afterwards.
With the MQTT implementation we want to reduce the logic required on the device to do such actions and move the logic to the server.
Example 1: ID of the device
You must know the ID of the device object to update data in it via REST. Also, this ID is required for every other data that needs to be associated with the device, for example, the source in a measurement, alarm or event.
To remove the necessity of persisting the ID on the device, Cumulocity IoT offers the identity API where you can link external IDs (for example a serial number) to the object, so you can query the ID any time.
A typical device start looks like this:
With MQTT, we automatically use the identity API with the MQTT clientId. This removes the necessity to tell the ID to the device, and because the client sends also the other data on this connection, we can associate every measurement, alarm, event, and so on with the correct device.
Example 2: ID of alarms
When a client creates an alarm using the REST API, it needs to ensure that it gets the ID of the alarm that was generated by Cumulocity IoT in return.
The client will need this ID to later update the alarm, for example, to status CLEARED, if the alarm is not active anymore.
In Cumulocity IoT, a device can only have a single alarm per type in status ACTIVE. If it creates another alarm with the same type, it will get de-duplicated. Therefore, the MQTT implementation uses the type of an alarm as identifier. The client only needs to send which type of alarm has been resolved, and the server will find the correct alarm object.
MQTT Static templates
Overview
To ease device integration Cumulocity IoT already supports a number of static templates that can be used by any client without the need to create your own templates. These templates focus on the most commonly used messages for device management purposes.
To use the templates listed below, you must publish the messages to the topic s/us (t/us for transient processing of published content, q/us for quiescent processing of published content or c/us for CEP processing of published content. Refer to SmartREST 1.0 > The protocol > Processing mode in the Reference guide for further information.
You must subscribe to the topic s/ds to receive operations with the static templates.
Templates quick reference
Click the commands below to see more information on the respective template. If a parameter is in square brackets, it is optional.
The client can receive the following templates when subscribing to s/ds.
Automatic device creation
The topic for static templates supports an automatic creation of devices. Whenever there is no child associated with your MQTT ClientID and you send data, Cumulocity IoT will automatically create a device for the MQTT ClientID. If you want to create the device on your own, your first message must be the device creation. In this case Cumulocity IoT will create the device from the template.
The automatic creation of devices is also supported for 1st level child devices. For child devices on a deeper level, you must use the template for creating a child device by sending it to the topic of the child device under the one you want to place the new child.
Handling non-mandatory parameters
If a parameter is not declared as mandatory, the client can send an empty string in that place.
100,,myType
Tailing commas is not required. The two lines below result in the same message.
100,,
100
Publish templates
The following templates can be used to publish data on the topics s/us as well as t/us. Refer to SmartREST 1.0 > The protocol > Processing mode in the Reference guide for more information about the t/ topic for transient data processing.
Inventory templates (1xx)
Device creation (100)
Create a new device for the serial number in the inventory if not yet existing. An externalId for the device with type c8y_Serial
and the device identifier of the MQTT clientId as value will be created.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | device name | NO | String | MQTT Device <serialNumber> |
2 | device type | NO | String | c8y_MQTTDevice |
Example
100,myDevice,myType
Child device creation (101)
Create a new child device for the current device. The newly created object will be added as child device. Additionally, an externaId for the child will be created with type c8y_Serial
and the value a combination of the serial of the root device and the unique child ID.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | unique child ID | YES | String | |
2 | device name | NO | String | MQTT Device <serialNumber> |
3 | device type | NO | String | c8y_MQTTChildDevice |
Example
101,uniqueChildId,myChildDevice,myChildType
Service creation (102)
Create a new software service for given device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | service unique external id | YES | String |
2 | service type | YES | String |
3 | service name | YES | String |
4 | service status | YES | String |
Example
102,myDatabaseDevice,systemd,DatabaseService,up
Service status update (104)
Set a status for given software service.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | service status | YES | String |
Example
104,up
Get child devices (105)
Trigger the sending of child devices of the device.
Example
105
Clear device’s fragment (107)
Remove one or more fragments from a device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1… | fragmentName | YES | String |
Example
107,c8y_Position,c8y_Configuration
Configure Hardware (110)
Update the hardware properties of the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | serialNumber | NO | String |
2 | model | NO | String |
3 | revision | NO | String |
Example
110,1234567890,myModel,1.2.3
Configure Mobile (111)
Update the mobile properties of the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | imei | NO | String |
2 | iccid | NO | String |
3 | imsi | NO | String |
4 | mcc | NO | String |
5 | mnc | NO | String |
6 | lac | NO | String |
7 | cellId | NO | String |
Example
111,1234567890,,54353
Configure Position (112)
Update the position properties of the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | latitude | NO | Number |
2 | longitude | NO | Number |
3 | altitude | NO | Number |
4 | accuracy | NO | Integer |
Example
112,50.323423,6.423423
Set Configuration (113)
Update the configuration properties of the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | configuration | NO | String |
Example
113,"val1=1\nval2=2"
Set supported operations (114)
Set the supported operations of the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1… | List of supported operations | NO | String |
Example
114,c8y_Restart,c8y_Configuration,c8y_SoftwareList
114, c8y_Restart,c8y_Configuration
in order to remove c8y_SoftwareList
after the request from the example above.Set firmware (115)
Set the firmware installed on the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | name | NO | String |
2 | version | NO | String |
3 | url | NO | String |
Example
115,firmwareName,firmwareVersion,firmwareUrl
Set software list (116)
Set the list of software installed on the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1… | List of 3 values per software | NO | (n/a) |
1.1 | name | NO | String |
1.2 | version | NO | String |
1.3 | url | NO | String |
Example
116,software1,version1,url1,software2,,url2,software3,version3
Set required availability (117)
Set the required interval for availability monitoring as an integer value representing minutes. For more information, see c8y_RequiredAvailability in Device management library > Device availability. This will only set the value if it does not exist. Values entered, for example, through the UI, are not overwritten.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | Required interval | NO | Integer |
Example
117,60
Set supported logs (118)
Set the supported logs of the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1… | List of supported logs | NO | String |
Example
118,ntcagent,dmesg,logread
Set supported configurations (119)
Set the supported configurations of the device.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1… | List of supported configurations | NO | String |
Example
119,modbus,system
Set currently installed configuration (120)
Set currently installed configuration of the device.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | Configuration type | YES | String | |
2 | Configuration file download URL | YES | String | |
3 | File name | NO | String | Configuration type |
4 | Date and time when the configuration was applied | NO | Date | Current date and time |
Example
120,myType,http://www.my.url,config.bin,2020-07-22T17:03:14.000+02:00
Set device profile that is being applied (121)
Set device profile that is being applied to the device.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | Profile executed | YES | String | |
2 | Profile ID | NO | String | Profile ID from the oldest EXECUTING device profile operation |
Example
121,true,8473
Set device agent information (122)
Allows a device to provide information about the agent running on it.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | Name of the agent | YES | String | |
2 | Version of the agent | YES | String | |
3 | The agent URL | NO | String | |
4 | Maintainer of the agent | YES | String |
Example
122,thin-edge.io,0.6,https://thin-edge.io,Software AG
Set advanced software list (140)
Sets the list of advanced software installed on the device. Any existing list will be overwritten.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | Name of the software | YES | String | |
2 | Version of the software | YES | String | |
3 | Type of the software | NO | String | |
4 | URL of the software | NO | String |
Example
140,docker,3.2.1,systemd,https://www.docker.com/,nginx,1.6,container,https://www.nginx.com/
Get the device managed object ID (123)
Retrieve the ID of the device managed object.
Example
123
Append advanced software items (141)
Appends advanced software items to the list that exists for the device.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | Name of the software | YES | String | |
2 | Version of the software | YES | String | |
3 | Type of the software | NO | String | |
4 | URL of the software | NO | String |
Example
141,docker,3.2.1,systemd,https://www.docker.com/,nginx,1.6,container,https://www.nginx.com/
Remove advanced software items (142)
Removes advanced software items from the list that exists for the device.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | Name of the software | YES | String | |
2 | Version of the software | YES | String |
Example
142,docker,3.2.1,nginx,1.6
Set supported software types (143)
Set the supported software types of the device. Ignores empty elements. An empty list removes the c8y_SupportedSoftwareTypes
fragment entirely.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1… | List of supported software types | NO | String |
Example
143,yum,docker
Measurement templates (2xx)
Create custom measurement (200)
Create a measurement with a given fragment and series.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | fragment | YES | String | |
2 | series | YES | String | |
3 | value | YES | Number | |
4 | unit | NO | String | |
5 | time | NO | Date | Current server time |
Example
200,c8y_Temperature,T,25
Create a custom measurement with multiple fragments and series (201)
Create a measurement with multiple fragments and series.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | type | YES | String | |
2 | time | NO | Date | |
3 | List of 4 values per fragment-series combination | YES | (n/a) | |
3.1 | fragment | YES | String | |
3.2 | series | YES | String | |
3.3 | value | YES | Number | |
3.4 | unit | NO | String |
Example
201,KamstrupA220Reading,2022-03-19T12:03:27.845Z,c8y_SinglePhaseEnergyMeasurement,A+:1,1234,kWh,c8y_SinglePhaseEnergyMeasurement,A-:1,2345,kWh,c8y_ThreePhaseEnergyMeasurement,A+:1,123,kWh,c8y_ThreePhaseEnergyMeasurement,A+:2,234,kWh,c8y_ThreePhaseEnergyMeasurement,A+:3,345,kWh
Create signal strength measurement (210)
Create a measurement of type c8y_SignalStrength
.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | rssi value | YES, if 2 not set | Number | |
2 | ber value | YES, if 1 not set | Number | |
3 | time | NO | Date | Current server time |
Example
210,-90,23,2016-06-22T17:03:14.000+02:00
Create temperature measurement (211)
Create a measurement of type c8y_TemperatureMeasurement
.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | temperature value | YES | Number | |
2 | time | NO | Date | Current server time |
Example
211,25,2016-06-22T17:03:14.000+02:00
Create battery measurement (212)
Create a measurement of type c8y_Battery
.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | battery value | YES | Number | |
2 | time | NO | Date | Current server time |
Example
212,95,2016-06-22T17:03:14.000+02:00
Alarm templates (3xx)
Create CRITICAL alarm (301)
Create a CRITICAL alarm.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | type | YES | String | |
2 | text | NO | String | Alarm of type alarmType raised |
3 | time | NO | Date | Current server time |
Example
301,c8y_TemperatureAlarm
Create MAJOR alarm (302)
Create a MAJOR alarm.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | type | YES | String | |
2 | text | NO | String | Alarm of type alarmType raised |
3 | time | NO | Date | Current server time |
Example
302,c8y_TemperatureAlarm,"This is an alarm"
Create MINOR alarm (303)
Create a MINOR alarm.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | type | YES | String | |
2 | text | NO | String | Alarm of type alarmType raised |
3 | time | NO | Date | Current server time |
Example
303,c8y_TemperatureAlarm
Create WARNING alarm (304)
Create a WARNING alarm.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | type | YES | String | |
2 | text | NO | String | Alarm of type alarmType raised |
3 | time | NO | Date | Current server time |
Example
304,c8y_TemperatureAlarm,,2013-06-22T17:03:14.000+02:00
Update severity of existing alarm (305)
Change the severity of an existing alarm.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | type | YES | String |
2 | severity | YES | String |
Example
305,c8y_TemperatureAlarm,CRITICAL
Clear existing alarm (306)
Clear an existing alarm.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | type | YES | String |
Example
306,c8y_TemperatureAlarm
Clear alarm’s fragment (307)
Remove one or more fragments from an alarm of a specific type.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | alarmType | YES | String |
2… | fragmentName | YES | String |
Example
307,c8y_TemperatureAlarm,c8y_Position,c8y_Configuration
Event templates (4xx)
Create basic event (400)
Create an event of given type and text.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | type | YES | String | |
2 | text | YES | String | |
3 | time | NO | Date | Current server time |
Example
400,c8y_MyEvent,"Something was triggered"
Create location update event (401)
Create typical location update event containing c8y_Position
.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | latitude | NO | Number | |
2 | longitude | NO | Number | |
3 | altitude | NO | Number | |
4 | accuracy | NO | Number | |
5 | time | NO | Date | Current server time |
Example
401,51.151977,6.95173,67
Create location update event with device update (402)
Create typical location update event containing c8y_Position
. Additionally the device will be updated with the same c8y_Position
fragment.
Position | Parameter | Mandatory | Type | Default value |
---|---|---|---|---|
1 | latitude | NO | Number | |
2 | longitude | NO | Number | |
3 | altitude | NO | Number | |
4 | accuracy | NO | Number | |
5 | time | NO | Date | Current server time |
Example
402,51.151977,6.95173,67
Clear event’s fragment (407)
Remove one or more fragments from an event of a specific type.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | eventType | YES | String |
2… | fragmentName | NO | String |
Example
407,c8y_MyEvent,c8y_Position,c8y_Configuration
Operation templates (5xx)
Get PENDING operations (500)
Trigger the sending of all PENDING operations for the agent.
Example
500
Set operation to EXECUTING (501)
Set the oldest PENDING operation with given fragment to EXECUTING.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | fragment | YES | String |
Example
501,c8y_Restart
Set operation to FAILED (502)
Set the oldest EXECUTING operation with given fragment to FAILED.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | fragment | YES | String |
2 | failureReason | NO | String |
Example
502,c8y_Restart,"Could not restart"
Set operation to SUCCESSFUL (503)
Set the oldest EXECUTING operation with given fragment to SUCCESSFUL.
It enables the device to send additional parameters that trigger additional steps based on the type of operation sent as fragment (see Section Updating operations).
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | fragment | YES | String |
2… | parameters | NO | String |
Example
503,c8y_Restart
Set operation to EXECUTING (504)
Set the operation with the given ID to EXECUTING. The operation must exist and must have the requesting device as the source.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | operationId | YES | String |
Example
504,123
Set operation to FAILED (505)
Set the operation with the given ID to FAILED. The operation must exist and must have the requesting device as the source.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | operationId | YES | String |
2 | failureReason | NO | String |
Example
505,123,"Could not restart"
Set operation to SUCCESSFUL (506)
Set the operation with given ID to SUCCESSFUL. The operation must exist and must have the requesting device as the source.
This may let the device send additional parameters that trigger further steps based on the type of the operation, also see Updating operations.
Position | Parameter | Mandatory | Type |
---|---|---|---|
1 | operationId | YES | String |
2… | parameters | NO | String |
Example
506,c8y_Restart
Subscribe templates
Inventory templates (1xx)
Get children of device (106)
List all children of the device.
Position | Parameter | Type |
---|---|---|
1… | child | String |
Example
106,child1,child2,child3
Get the device managed object ID (124)
Retrieve the ID of the device managed object.
Position | Parameter | Type |
---|---|---|
1 | id | String |
Example
124,12345
Operation templates (5xx)
All operation responses have the same base structure, leading with the message ID and followed by the ID of either the root device or a child which should handle the operation.
Restart (510)
Restart a device.
Example
510,DeviceSerial
Command (511)
Run the command being sent in the operation.
Position | Parameter | Type |
---|---|---|
1 | Command text | String |
Example
511,DeviceSerial,execute this
Configuration (513)
Set the configuration being sent in the operation.
Position | Parameter | Type |
---|---|---|
1 | configuration | String |
Example
513,DeviceSerial,"val1=1\nval2=2"
Firmware (515)
Install the firmware from the url.
Position | Parameter | Type |
---|---|---|
1 | firmware name | String |
2 | firmware version | String |
3 | url | String |
Example
515,DeviceSerial,myFirmware,1.0,http://www.my.url
Software list (516)
Install the software sent in the operation.
Position | Parameter | Type |
---|---|---|
1… | List of 3 values per software | (n/a) |
1.1 | name | String |
1.2 | version | String |
1.3 | url | String |
Example
516,DeviceSerial,softwareA,1.0,url1,softwareB,2.0,url2
Measurement request operation (517)
Send the measurements specified by the request name.
Position | Parameter | Type |
---|---|---|
1 | request name | String |
Example
517,DeviceSerial,LOGA
Relay (518)
Open or close the relay.
Position | Parameter | Type |
---|---|---|
1 | Relay state | String |
Example
518,DeviceSerial,OPEN
RelayArray (519)
Open or close the relays in the array.
Position | Parameter | Type |
---|---|---|
1… | List of relay state | String |
Example
519,DeviceSerial,OPEN,CLOSE,CLOSE,OPEN
Upload configuration file (520)
The current configuration is uploaded from Cumulocity IoT to the device.
Example
520,DeviceSerial
Download configuration file (521)
Download a configuration file from the URL.
Position | Parameter | Type |
---|---|---|
1 | url | String |
Example
521,DeviceSerial,http://www.my.url
Logfile request (522)
Upload a log file for the given parameters.
Position | Parameter | Type |
---|---|---|
1 | Log file name | String |
2 | Start date | Date |
3 | End date | Date |
4 | Search text | String |
5 | Maximum lines | Integer |
Example
522,DeviceSerial,logfileA,2013-06-22T17:03:14.000+02:00,2013-06-22T18:03:14.000+02:00,ERROR,1000
Communication mode (523)
Change the communication mode.
Position | Parameter | Type |
---|---|---|
1 | mode | String |
Example
523,DeviceSerial,SMS
Download configuration file with type (524)
Download a configuration file from the URL with type.
Position | Parameter | Type |
---|---|---|
1 | URL | String |
2 | configuration type | String |
Example
524,DeviceSerial,http://www.my.url,type
Firmware from patch (525)
Install the firmware from the patch.
Position | Parameter | Type |
---|---|---|
1 | firmware name | String |
2 | firmware version | String |
3 | URL | String |
4 | dependency | String |
Example
525,DeviceSerial,firmwareName,1.0,http://www.my.url,dependency
Upload configuration file with type (526)
Configuration is uploaded from Cumulocity IoT to the device with type.
Position | Parameter | Type |
---|---|---|
1 | configuration type | String |
Example
526,DeviceSerial,type
Set device profiles (527)
Set the device profiles
Position | Parameter | Type |
---|---|---|
1 | firmware marker | (n/a) |
1… | 5 values of firmware | (n/a) |
1.1 | firmware name | String |
1.2 | firmware version | String |
1.3 | firmware URL | String |
1.4 | firmware isPatch | String |
1.5 | firmware dependency | String |
2 | software marker | (n/a) |
2… | List of 4 values per software | (n/a) |
2.1 | software name | String |
2.2 | software version | String |
2.3 | software URL | String |
2.4 | software action | String |
3 | configuration marker | (n/a) |
3… | List of 2 values per configuration | (n/a) |
3.1 | configuration URL | String |
3.2 | configuration type | String |
Example
527,DeviceSerial,$FW,firmwareName,1.0,http://www.my.url,true,dependency,$SW,softwareA,1.0,http://www.my.url1,action1,softwareB,2.0,http://www.my.url2,action2,$CONF,http://www.my.url1,type1,http://www.my.url2,type2
Update software (528)
Update the software installed on the device.
Position | Parameter | Type |
---|---|---|
1… | List of 4 values per software | (n/a) |
1.1 | name | String |
1.2 | version | String |
1.3 | URL | String |
1.4 | action | String |
Example
528,DeviceSerial,softwareA,1.0,url1,install,softwareB,2.0,url2,install
The action can either be install
or delete
.
When the install
action is received, the device agent ensures that the software will appear in the c8y_SoftwareList
fragment of the device after it has completed the installation.
The agent will also determine if there is a previous version of the software and replace it with the new version, resulting in an update.
When the delete
action is received, the device agent ensures that the software will no longer appear in the c8y_SoftwareList
fragment of the device after the software update operation has completed.
Update advanced software (529)
Update the software installed on the device.
Position | Parameter | Type |
---|---|---|
1… | List of 5 values per software | (n/a) |
1.1 | name | String |
1.2 | version | String |
1.2 | type | String |
1.3 | URL | String |
1.4 | action to be performed | String |
Example
529,DeviceSerial,softwareA,1.0,url1,install,softwareB,2.0,url2,install
Cloud Remote Access connect (530)
Establish tunneling by Remote Access device agent.
Position | Parameter | Type |
---|---|---|
1 | hostname | String |
2 | port | Integer |
3 | connection key | String |
Example
530,DeviceSerial,10.0.0.67,22,eb5e9d13-1caa-486b-bdda-130ca0d87df8
Updating operations
When using the template to set an operation to status SUCCESSFUL, it supports sending additional parameters to trigger additional calls on the server. The table below shows the operations supporting this feature and what will be done with the parameters.
Fragment | Parameters | Action triggered |
---|---|---|
c8y_Command | result | Result will be added to operation |
c8y_RelayArray | relay states | Device object will be updated with the states |
c8y_CommunicationMode | no parameter needed | Device object will be updated with the mode |
c8y_LogfileRequest | file url | File url will be added to operation |
c8y_DownloadConfigFile | (optional) timestamp | Device object will be updated with the ID of the configuration dump and the timestamp (or server time) |
JSON via MQTT
This section describes the JSON payload format that can be used with the Cumulocity IoT MQTT implementation.
Compared to SmartREST 2.0 – which only works with fixed templates – JSON’s support for MQTT was designed to combine the payload flexibility of our REST API with the low protocol overhead of MQTT.
The SmartREST way should still be the preferred way if it is important to reduce your payload to the minimum (mobile traffic, low capability device).
Topic structure
The topic structure in JSON MQTT is quite similar to the REST endpoints. The main difference is in the additional action part which is included in the topic.
To publish messages:
<api>/<resource>/<action>/<resource_id>
To publish messages in transient mode:
t/<api>/<resource>/<action>/<resource_id>
To publish messages in quiescent mode:
q/<api>/<resource>/<action>/<resource_id>
To publish messages in CEP mode:
c/<api>/<resource>/<action>/<resource_id>
<resource_id>
is not required for every <action>
. See the examples below.Refer to Processing mode for more information about transient, quiescent and CEP data processing.
Topic actions
The action in the topic corresponds to the HTTP methods combined with the content-type header.
The following actions are available:
- create - corresponds to HTTP POST
- createBulk - corresponds to HTTP POST with the content-type header value set to collection media type, for example
application/vnd.com.nsn.cumulocity.measurementCollection+json;charset=UTF-8;ver=0.9
- update - corresponds to HTTP PUT
- delete - corresponds to HTTP DELETE
Supported endpoint
The current JSON MQTT implementation does not cover all SmartREST 2.0 operations, so for example the whole device bootstrap process must be done using SmartREST 2.0.
The following endpoints and actions are supported:
Endpoint | create | createBulk | update | delete |
---|---|---|---|---|
event/events | x | x | x | x |
alarm/alarms | x | x | x | |
measurement/measurements | x | x | x | |
inventory/managedObjects | x | x | ||
inventory/managedObjects/{id}/childDevices | x |
If the operation is not supported, a proper error message will be sent to the error topic.
For all of the above endpoints, you can use the same payload like in the REST API. The only difference is in the “source” field - in REST this field is mandatory while for JSON MQTT there is no need to set the device ID here. The source device ID will automatically be resolved based on the MQTT client ID. This value will always be used no matter if something is already defined there.
Examples
Create new event
Publish a message on topic /event/events/create with payload:
{
"type": "TestEvent",
"text": "sensor was triggered",
"time": "2014-03-03T12:03:27.845Z"
}
Create many events
Publish a message on topic /event/events/createBulk with payload:
{
"events": [
{
"type": "TestEvent1",
"text": "sensor was triggered",
"time": "2014-03-03T12:03:27.845Z"
},
{
"type": "TestEvent2",
"text": "sensor was triggered",
"time": "2014-03-04T12:03:27.845Z"
}
]
}
Update event
Publish a message on topic /event/events/update/<event_id> with payload:
{
"text": "new text"
}
Delete event
Publish a message on topic /event/events/delete/<event_id> with empty payload.
Create a measurement data point
Publish a message on topic measurement/measurements/create with payload:
{
"type": "c8y_TemperatureMeasurement",
"time": "2021-09-06T17:35:14.000+02:00",
"c8y_TemperatureMeasurement": {
"T": {
"value": 20,
"unit": "C"
}
}
}
Error handling
Use the error topic to subscribe for errors related to the JSON MQTT implementation. In case of invalid payload, wrong topic or any other exception, a notification will be published on this topic. The payload is in JSON format. Besides a standard error message, it also contains a message ID which helps the client in finding out which exact message was failing.
Example payload:
{
"error": "undefined/validationError",
"message": "Following mandatory fields should be included: severity,text,time",
"messageId": 3
}
Receiving operations
A notification client can subscribe to the devicecontrol/notifications topic to receive notifications of newly created operations. Initially upon subscription, all operations which are not yet forwarded will be published.
Additionally, it contains an External ID, so the client can identify for which child the operation is executed.
Example notification:
{
"agentId": "1",
"creationTime": "2018-05-17T07:33:15.555Z",
"delivery": {
"log": [
],
"status": "PENDING",
"time": "2018-05-17T07:33:15.575Z"
},
"deviceId": "2",
"id": "123",
"status": "PENDING",
"c8y_Command": {
"text": "Do something"
},
"description": "Execute shell command",
"externalSource": {
"externalId": "3",
"type": "c8y_Serial"
}
}