Overview
The MQTT implementation of Cumulocity IoT provides the following benefits:
- Multi-tenancy support: A single endpoint serves multiple tenants.
- Device identity management: Devices authenticate using device-specific credentials.
- Device registration: Non-personalized devices can be deployed by pairing them with Cumulocity IoT tenants.
- Device management: Rich, pre-defined device management payload formats to enable out-of-the-box management of millions of devices.
- Standard IoT payload formats: Pre-defined payload formats to support IoT sensor readings, alarm management, remote control and device hierarchies.
- Custom payload formats: Additional payload formats can be added.
- Minimum traffic overhead.
- Processing modes: Control whether data is persisted in Cumulocity IoT database, transiently passed to real-time processing, processed using quiescent mode which ensures that real-time notifications are disabled or is processed using CEP mode that ensures data is transiently sent to real-time processing engine only with real-time notifications disabled.
- Full bi-directional communication.
- MQTT over WebSockets support.
- TLS support.
- Full horizontal scalability.
The MQTT section is structured as follows:
- MQTT implementation gives a detailed reference of protocol-level aspects in the Cumulocity IoT implementation of MQTT.
- Device integration walks you through the process of interfacing devices with Cumulocity IoT through MQTT.
- SmartREST 1.0 defines the SmartREST 1.0 payload format for MQTT for easy portability of existing SmartREST devices.
- SmartREST 2.0 defines the SmartREST 2.0 payload format for MQTT with improvements in usability and traffic usage.
- MQTT static templates provides a reference of pre-defined payload formats that you can use straight away.
- Handling IDs describes how IDs are handled in the Cumulocity IoT MQTT protocol.
- JSON via MQTT describes the payload format that can be used with the Cumulocity IoT MQTT implementation.
This section does not describe the basics of MQTT communication. If you are unfamiliar with MQTT, we recommend consulting one of the numerous introductions in the Internet. Some references can be found on the MQTT web site.
Info: For all MQTT connections to the platform, the maximum accepted payload size is 16184 bytes (16KiB), which includes both message header and body. The header size varies, but its minimum is 2 bytes.
MQTT implementation
This section will list the implementation details for the MQTT protocol. The Cumulocity IoT implementation supports MQTT Version 3.1.1.
Connecting via MQTT
Cumulocity IoT supports MQTT both via TCP and WebSockets. As URL you can use the domain of the instance in the format mqtt.<instance_domain> (e.g. mqtt.cumulocity.com) or your tenant domain (e.g. mytenant.cumulocity.com/mqtt).
Available ports:
TCP | WebSockets | |
---|---|---|
one-way SSL | 8883 | 443 |
no SSL | 1883 | 80 |
experimental two-way SSL | 1884 | - |
For experimental two-way SSL the port 1884 has to be enabled. To do that, add the following rule to Chef:
"MQTTClientCert" => {
"enabled" => true,
"enableTransparentSSLPort" => false
}
enabled
- Open the port 1884 and let devices authorize using a certificate with TCP (it is not available with WebSockets right now).enableTransparentSSLPort
- Redirect the whole communication (ports) from 1883 to 1884 (usefalse
since handling client authorization via username and password is not implemented yet), so right now it will enforce using certificates by devices also on 1883 port (which is highly not recommended).
Info: To use WebSockets you need to connect to the path /mqtt and follow the MQTT standard for WebSocket communication.
SmartREST payload
The Cumulocity IoT MQTT implementation uses SmartREST as a payload. SmartREST is a CSV-like message protocol that uses templates on the server side to create data in Cumulocity IoT.
Info: For all MQTT connections to the platform, the maximum accepted payload size is 16184 bytes, which includes both message header and body. The header size varies, but its minimum is 2 bytes.
SmartREST basics
A SmartREST message is a single row in which each parameter is separated by comma. The first parameter is an ID that defines the message. You can send multiple messages in a single publish by using a line break between messages.
SmartREST escaping
The CSV (comma-separated values) format is used for communication with the SmartREST endpoint. The following rules must be followed to ensure a frictionless communication.
- Every row must be terminated by the
\n
character sequence. - Values are always separated by a comma (
,
). - If a value contains double-quotes (
"
), commas (,
), leading or trailing whitespaces, line-breaks (\n
), carriage returns (\r
) or tab stops, it must be surrounded by quotes ("
). Contained double-quotes ("
) must be escaped by prepending a backslash (\
).
The same escaping rules apply to messages that will be sent from the server to the client.
Publish example:
100,"This value, needs escaping",This value does not need escaping
Subscribe example:
511,myDeviceSerial,"execute this\nand this\nand \"this\""
Info:
\n
does not create a new line in the output (e.g. console, UI); to achieve this, a new line character (ASCII 0A) needs to be used.
Device hierarchies
MQTT sessions are linked to a single device, but this device can have a freely configurable device hierarchy below it.
All children require a unique ID defined when creating the device. We recommend using a combination of the unique ID of the root device and a unique ID within the hierarchy.
To create data for a child instead of the root device, the unique ID of the child is added as another section in the topic (e.g. s/us/myChildDeviceIdentifier).
The client will automatically receive operations for every child in the hierarchy by subscribing to the respective topic. It is not required to subscribe for each child.
Every operation received will contain the template ID followed by the ID of the device/child for which the operation was created (followed by other operation parameters).
MQTT features
MQTT authentication
MQTT supports setting a username and a password. To connect to Cumulocity IoT, the MQTT username needs to include both tenant ID and username in the format <tenantID/username>.
MQTT ClientId
The MQTT ClientId is a field to uniquely identify each connected client. The Cumulocity IoT implementation also uses the ClientId to link the client directly to a device. Therefore the following format should be used for the ClientId:
“connectionType:deviceIdentifier:defaultTemplateIdentifier”
Field | Mandatory | Description |
---|---|---|
connectionType | NO | Indication of connection type default: d (device) |
deviceIdentifier | YES | A unique identifier for your device, e.g. IMEI, Serial number |
defaultTemplateIdentifier | NO | Check the SmartREST section for more information about template identifiers |
For the simplest version of a client, the MQTT clientId can just be the deviceIdentfier. It will automatically be interpreted as device connection.
Example ClientIds:
mySerialNumber
d:mySerialNumber
d:mySerialNumber:myDefaultTemplate
The uniqueness of the MQTT ClientId is determined only by the deviceIdentifier. Therefore from the above examples only one client can be connected at the same time.
During a SSL connection with certificates, the deviceIdentifier
has to match the Common Name of the used certificate (first certificate in the chain, which is provided by the device).
MQTT Quality of Service
The Cumulocity IoT implementation supports all 3 levels of MQTT QoS:
- QoS 0: At most once
- The client just sends the message once (fire and forget)
- No reaction from the server
- QoS 1: At least once
- The client repeats the message until it receives a server acknowledgement
- QoS 2: Exactly once
- The client sends a message
- The server acknowledges (holds the message)
- The client sends a release command
- The server processes the messages and acknowledges again
For subscriptions to the operation or error topics, we will deliver all messages in the QoS which the client defined when subscribing to the topic.
MQTT clean session
MQTT clients can set the clean session flag to “0” (false). This will ensure that in case the client disconnects, your subscription will still work and when you reconnect the client will receive the missed messages.
Info: Cumulocity IoT requires clean session to be set to “1” (true). Currently we cannot guarantee that disabling clean session will work reliably, hence we recommend to always enable clean session.
MQTT retained flag
In the current Cumulocity IoT implementation, subscriptions to topics where devices publish data are not allowed. Publishing data with the retained flag on this topic is allowed but has no practical difference to sending it without the flag. Messages published by Cumulocity IoT like operations and errors do not contain the retained flag.
MQTT last will
In MQTT, the “last will” is a message that is specified at connection time and that is executed when the client loses the connection. For example, using 400,c8y_ConnectionEvent,"Device connection was lost."
as last will message and s/us as last will topic, raises an event whenever the device loses the connection.
Info: The execution of the “last will” updates the device availability.
Debugging
To support developers during development, it is possible to subscribe to the topic s/e. On this topic the device can retrieve debug and error messages that occur during a publish from the device.
Info: This topic is purely designed to support the development of clients. It is not recommended to always subscribe to this channel as the messages are verbose and can significantly increase the data usage. Also, you should not use this topic to trigger actions of the device based on what you receive on the topic. It is not a response channel.
Device integration
Overview
The basic life cycle for integrating devices into Cumulocity IoT is discussed in Interfacing devices.
In this section, we will show how this life cycle can be managed using the MQTT implementation.
The life cycle consists of two phases, a startup phase and a cycle phase.
The startup phase can be as short as just checking the credentials:
- Step 0: Request device credentials, if they have not been requested yet.
- Step 1: Ensure that the device exists.
- Step 2: Ensure that the device children exist.
- Step 3: Subscribe to the topics.
The cycle phase consists of two kinds of actions:
Startup phase
Step 0: Request device credentials
In Cumulocity IoT, every MQTT connection needs to be authenticated. You can use the device credentials topics in the MQTT implementation to generate new credentials for a device.
Once the device retrieved the credentials, it needs to store them locally for further connections.
To establish a connection you need to configure the following parameters:
- Host: <your_cumulocity_url>
- User: <tenantID>/<username>
- Password: <your_cumulocity_password>
For more information, refer to the Hello MQTT section.
The process works as follows:
- Cumulocity IoT assumes that each device has some form of unique ID. For instance, a good device identifier can be the MAC address of the network adapter, the IMEI of a mobile device or a hardware serial number.
- When you take a new device into use, you enter this unique ID into Device registration in the Device Management application in Cumulocity IoT, and start the device.
- The device will use this ID as part of the MQTT ClientId and static user credentials that can be enquired at the Software AG Empower Portal.
- The device subscribes to the topic s/dcr.
- The device starts publishing continuous empty messages on the topic s/ucr to notify the server that it is ready to retrieve credentials.
- Next, you must accept the connection from the device in the Device Registration page.
- When the device sends the next empty message it should receive credentials in the format
70,<tenantID>,<username>,<password>
After receiving the credentials, the device can close the MQTT connection and create a new one with the received credentials.
Step 1: Verify device
As MQTT supports an automatic device creation if the client sends data and there is no device present, this step is only required if you want to create the device manually.
The device creation can be achieved by employing the static template 100. This template can be blindly used on every boot of the device as it will only create the device if it is not already present.
The device will be linked automatically to the ID the client uses with its MQTT ClientId.
100,Device Name,Device Type
Info: The topic used for Cumulocity IoT’s pre-provided static templates is s/us.
Step 2: Verify children
Like the root device, also children of it are covered by the automatic device creation.
To handle this step manually you can send the static template 101 for creating a child device. The template will only create the child if it does not already exist.
101,Unique Child ID,Child Name,Child Type
Step 3: Subscribe topics
If the device supports operations, it should subscribe to all required topics (static templates and SmartREST 2.0).
Cycle phase
Step A: Send CSV data
While the device holds an active MQTT connection, it can publish either on the topics for static templates or on the topics for a SmartREST template to send data to the server.
Based on the MQTT ClientId, the physical device is directly connected to the device object in Cumulocity IoT. Therefore, the data you send is automatically connected to the device.
To send data to a child device, publish the data to the topics described in Device hierarchies.
Step B: Receive CSV operations
By subscribing to a topic the device automatically tells Cumulocity IoT that it wants to receive operations. Any operation created will be automatically parsed using either the static templates or the templates the device defines.
SmartREST 1.0
This section describes how you can use your existing SmartREST 1.0 templates with MQTT.
Note that SmartREST 1.0 was designed for HTTP request/response and does not support the ID-less communication with MQTT. It only uses the MQTT connection to send exactly the same request as you would send using HTTP. Therefore, it comes with some limitations as MQTT is not request/response.
The support for SmartREST 1.0 was added to ease transition if you have an existing implementation using it.
Info: If you start a new device integration, we highly recommend to use SmartREST 2.0.
For general information on SmartREST 1.0, refer to Using the REST interface > Using SmartREST in the Microservice SDK guide.
MQTT ClientId
Although you need to send the IDs in the body of each message with SmartREST 1.0, it is still important to connect with the correct MQTT ClientId.
The MQTT ClientId needs to match the externalId with type c8y_Serial of your device. It is used to assign the correct operations and responses.
Sending SmartREST 1.0
To send data to the server you can publish the same content as you would POST to the SmartREST endpoint /s.
The X-ID header is part of the topic the client needs to publish on.
s/ul/<X-ID>
Processing mode
Since the Cumulocity IoT SmartREST protocol supports TRANSIENT processing mode for avoiding storage of sent data in the database, publishing on MQTT t/ topic instead of s/ topic will only pass the data to real-time processing.
t/ul/<X-ID>
The Cumulocity IoT SmartREST protocol also supports QUIESCENT processing mode for avoiding real-time notifications by publishing on MQTT q/ topic instead of s/ topic. Currently, the QUIESCENT processing mode is applicable for measurements and events only.
q/ul/<X-ID>
The Cumulocity IoT SmartREST protocol also supports CEP processing mode to ensure that data is only sent to the real-time event processing engine with real-time notifications, disabled by publishing on MQTT c/ topic instead of s/ topic. Currently, the CEP processing mode is applicable for measurements and events only.
c/ul/<X-ID>
Receiving SmartREST 1.0
If a template triggers a response template, the returning message will be published by the server on the following topic.
s/dl/<X-ID>
This topic can be subscribed by the client.
Receiving operations
SmartREST 1.0 via HTTP offers the /devicecontrol/notifications endpoint to listen to realtime operations. You can receive the same content on the following MQTT topic.
s/ol/<X-ID>
Limitations
MQTT currently does not support request/response. Therefore, if you send a request on the publish topic and receive a response on the subscribe topic, the client cannot securely match that they belong together.
You can counter this limitation by designing the templates in a way that you never need to know what request triggered the response, and the client automatically knows it by the messageId.
SmartREST 2.0
Overview
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 > 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 e.g. 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 need to 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).
Info: If the message rate limit per second is exceeded, the requests are delayed and kept in queue. If the queue limit number is exceeded, the client messages are rejected and the client is disconnected.
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.
Important: POST Inventory templates start with the value of the externalId after the msgId. Leaving this column empty will result in not creating an external ID.
# Creation:
10,100,POST,INVENTORY,,c8y_MySerial
10,101,POST,INVENTORY,,
# 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 (e.g. 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
Info: If you use a default X-ID, you need to include in the ClientId the
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).
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 need to 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 > Processing mode in the Reference guide for further information.
You need to subscribe to the topic s/ds to receive operations with the static templates.
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 none 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 > 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 | Default |
---|---|---|---|
1 | device name | NO | MQTT Device <serialNumber> |
2 | device type | NO | 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 | Default |
---|---|---|---|
1 | unique child ID | YES | |
2 | device name | NO | MQTT Device <serialNumber> |
3 | device type | NO | c8y_MQTTChildDevice |
Example
101,uniqueChildId,myChildDevice,myChildType
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 |
---|---|---|
1… | fragmentName | YES |
Example
107,c8y_Position,c8y_Configuration
Configure Hardware (110)
Update the hardware properties of the device.
Position | Parameter | Mandatory |
---|---|---|
1 | serialNumber | NO |
2 | model | NO |
3 | revision | NO |
Example
110,1234567890,myModel,1.2.3
Configure Mobile (111)
Update the mobile properties of the device.
Position | Parameter | Mandatory |
---|---|---|
1imei | NO | |
2 | iccid | NO |
3 | imsi | NO |
4 | mcc | NO |
5 | mnc | NO |
6 | lac | NO |
7 | cellId | NO |
Example
111,1234567890,,54353
Configure Position (112)
Update the position properties of the device.
Position | Parameter | Mandatory |
---|---|---|
1 | latitude | NO |
2 | longitude | NO |
3 | altitude | NO |
4 | accuracy | NO |
Example
112,50.323423,6.423423
Set Configuration (113)
Update the configuration properties of the device.
Position | Parameter | Mandatory |
---|---|---|
1 | configuration | NO |
Example
113,"val1=1\nval2=2"
Set supported operations (114)
Set the supported operations of the device.
Position | Parameter | Mandatory |
---|---|---|
1… | List of supported operations | NO |
Example
114,c8y_Restart,c8y_Configuration,c8y_SoftwareList
Set firmware (115)
Set the firmware installed on the device.
Position | Parameter | Mandatory |
---|---|---|
1 | name | NO |
2 | version | NO |
3 | url | NO |
Example
115,firmwareName,firmwareVersion,firmwareUrl
Set software list (116)
Set the list of software installed on the device.
Position | Parameter | Mandatory |
---|---|---|
1… | List of 3 values per software | NO |
1.1 | name | NO |
1.2 | version | NO |
1.3 | url | NO |
Example
116,software1,version1,url1,software2,,url2,software3,version3
Set required availability (117)
Set the required interval for availability monitoring. It will only set the value if it does not exist. Values entered, e.g. through UI, are not overwritten.
Position | Parameter | Mandatory |
---|---|---|
1 | Required interval | NO |
Example
117,60
Measurement templates (2xx)
Create custom measurement (200)
Create a measurement with a given fragment and series.
Position | Parameter | Mandatory | Default |
---|---|---|---|
1 | fragment | YES | |
2 | series | YES | |
3 | value | YES | |
4 | unit | NO | |
5 | time | NO | Current server time |
Example
200,c8y_Temperature,T,25
Create signal strength measurement (210)
Create a measurement of type c8y_SignalStrength.
Position | Parameter | Mandatory | Default |
---|---|---|---|
1 | rssi value | YES, if 2 not set | |
2 | ber value | YES, if 1 not set | |
3 | time | NO | 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 | Default |
---|---|---|---|
1 | temperature value | YES | |
2 | time | NO | 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 | Default |
---|---|---|---|
1 | battery value | YES | |
2 | time | NO | 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 | Default |
---|---|---|---|
1 | type | YES | |
2 | text | NO | Alarm of type alarmType raised |
3 | time | NO | Current server time |
Example
301,c8y_TemperatureAlarm
Create MAJOR alarm (302)
Create a MAJOR alarm.
Position | Parameter | Mandatory | Default |
---|---|---|---|
1 | type | YES | |
2 | text | NO | Alarm of type alarmType raised |
3 | time | NO | Current server time |
Example
302,c8y_TemperatureAlarm,"This is an alarm"
Create MINOR alarm (303)
Create a MINOR alarm.
Position | Parameter | Mandatory | Default |
---|---|---|---|
1 | type | YES | |
2 | text | NO | Alarm of type alarmType raised |
3 | time | NO | Current server time |
Example
303,c8y_TemperatureAlarm
Create WARNING alarm (304)
Create a WARNING alarm.
Position | Parameter | Mandatory | Default |
---|---|---|---|
1 | type | YES | |
2 | text | NO | Alarm of type alarmType raised |
3 | time | NO | 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 |
---|---|---|
1 | type | YES |
2 | severity | YES |
Example
305,c8y_TemperatureAlarm,CRITICAL
Clear existing alarm (306)
Clear an existing alarm.
Position | Parameter | Mandatory |
---|---|---|
1 | type | YES |
Example
306,c8y_TemperatureAlarm
Clear alarm’s fragment (307)
Remove one or more fragments from an alarm of a specific type.
Position | Parameter | Mandatory |
---|---|---|
1 | alarmType | YES |
2… | fragmentName | YES |
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 | Default |
---|---|---|---|
1 | type | YES | |
2 | text | YES | |
3 | time | NO | 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 | Default |
---|---|---|---|
1 | latitude | NO | |
2 | longitude | NO | |
3 | altitude | NO | |
4 | accuracy | NO | |
5 | time | NO | 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 | Default |
---|---|---|---|
1 | latitude | NO | |
2 | longitude | NO | |
3 | altitude | NO | |
4 | accuracy | NO | |
5 | time | NO | 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 |
---|---|---|
1 | eventType | YES |
2… | fragmentName | NO |
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 |
---|---|---|
1 | fragment | YES |
Example
501,c8y_Restart
Set operation to FAILED (502)
Set the oldest EXECUTING operation with given fragment to FAILED.
Position | Parameter | Mandatory |
---|---|---|
1 | fragment | YES |
2 | failureReason | NO |
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 |
---|---|---|
1 | fragment | YES |
2… | parameters | NO |
Example
503,c8y_Restart
Subscribe templates
The client can receive the following templates when subscribing to s/ds.
Inventory templates (1xx)
Get children of device (106)
List all children of the device.
Position | Parameter |
---|---|
1… | child |
Example
106,child1,child2,child3
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 |
---|---|
1 | Command text |
Example
511,DeviceSerial,execute this
Configuration (513)
Set the configuration being sent in the operation.
Position | Parameter |
---|---|
1 | configuration |
Example
513,DeviceSerial,"val1=1\nval2=2"
Firmware (515)
Install the firmware from the url.
Position | Parameter |
---|---|
1 | firmware name |
2 | firmware version |
3 | url |
Example
515,DeviceSerial,myFimrware,1.0,http://www.my.url
Software list (516)
Install the software sent in the operation.
Position | Parameter |
---|---|
1… | List of 3 values per software |
1.1 | name |
1.2 | version |
1.3 | url |
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 |
---|---|
1 | request name |
Example
517,DeviceSerial,LOGA
Relay (518)
Open or close the relay.
Position | Parameter |
---|---|
1 | Relay state |
Example
518,DeviceSerial,OPEN
RelayArray (519)
Open or close the relays in the array.
Position | Parameter |
---|---|
1… | List of relay state |
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 |
---|---|
1 | url |
Example
521,DeviceSerial,http://www.my.url
Logfile request (522)
Upload a log file for the given parameters.
Position | Parameter |
---|---|
1 | Log file name |
2 | Start date |
3 | End date |
4 | Search text |
5 | Maximum lines |
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 |
---|---|
1 | mode |
Example
523,DeviceSerial,SMS
Updating operations
When using the template to set an operation to state 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) |
Handling 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 need to 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, e.g. 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 (e.g. 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, etc. 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, e.g. 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.
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>/<id>
To publish messages in transient mode:
t/<api>/<resource>/<action>/<id>
To publish messages in quiescent mode:
q/<api>/<resource>/<action>/<id>
To publish messages in CEP mode:
c/<api>/<resource>/<action>/<id>
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 has to 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/<DeviceID>/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.
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"
}
}