MQTT

The MQTT implementation of Cumulocity 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 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 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.

Also see our SmartREST documentation.

This section does not describe the basics of MQTT communication. If you are unfamiliar with MQTT, we recommend you to consult one of the numerous introductions in the Internet. Some references can be found on the MQTT website.

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.

Integration life cycle

The basic life cycle for integrating devices into Cumulocity 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:

MQTT phases

Requirements
  • Access via bootstrap user credentials. See Device credentials for more information on how to obtain and use bootstrap credentials.

Startup phase

Step 0: Request device credentials

In Cumulocity, every MQTT connection must 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 must configure the following parameters:

  • Host: <your_cumulocity_url>
  • User: <tenantID>/<username> (user alias is not supported)
  • Password: <your_cumulocity_password>

For more information, refer to the Hello MQTT section.

The process works as follows:

  • Cumulocity 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, and start the device.
  • The device will use this ID as part of the MQTT ClientId and static user credentials that can be enquired from product support.
  • 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’s pre-provided static templates is s/us.

Step 2: Verify children

Like the root device, also its children 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. 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 that it wants to receive operations. Any operation created will be automatically parsed using either the static templates or the templates the device defines.

MQTT implementation

This section lists the implementation details for the MQTT protocol. The Cumulocity implementation supports MQTT Version 3.1.1.

Connecting via MQTT

Cumulocity supports MQTT both via TCP and WebSockets. As URL you can use the domain of the instance in the format mqtt.<instance_domain> (for example mqtt.cumulocity.com) or your tenant domain (for example mytenant.cumulocity.com/mqtt).

Available ports:

  TCP WebSockets
SSL 8883 443
no SSL 1883 80
Info
Port 80 is deactivated in cloud systems.

Port 8883 supports two types of SSL: two-way SSL using certificates for client authorization and one-way SSL using username and password for client authorization. The two-way SSL support is enabled by default. To disable it please contact product support.

Info
To use WebSockets you must connect to the path /mqtt and follow the MQTT standard for WebSocket communication.

SmartREST payload

The Cumulocity 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. It incorporates the highly expressive strength of the REST API but replaces JSON with comma-separated values (CSV) to avoid the complexity of JSON parsing for embedded devices. Additionally, the simple and compact syntax of CSV renders it highly efficient for IoT communication via mobile networks. It can save up to 80% of mobile traffic compared to other HTTP APIs.

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 (for example console, UI); to achieve this, a new line character (ASCII 0A) must 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 you to use 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 (for example 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

The communication with Cumulocity employing MQTT supports authentication in two ways:

  • Username and password. The MQTT username must include the tenant ID and username in the format <tenantID/username>.
  • Device certificates. For secure communication, devices must contain the entire chain of certificates leading to the trusted root certificate, or if only the device certificate is provided, then the immediate issuer certificate must be uploaded to the platform’s truststore. Also, they must contain the server certificate in their truststore.

Troubleshooting

A device sends correct username and password, but incorrect certificate at the same time

If the platform is configured to support two-way SSL, your devices have a configured keystore with invalid certificates, and you want to use basic authorization, we recommend you to turn off sending certificates during connection. Certificates may be invalid because they expired or the root certificate is not uploaded to the platform. Turn off certificate sending in the device’s software. If that is not possible, to make the connection work, check the following:

  • The platform’s trust store cannot be empty. At least one trusted certificate must be uploaded to the platform.
  • The device’s MQTT client must be configured to not send certificates if it does not find its root certificate in the accepted issuers list returned by the server during handshake. In most cases this happens automatically. It is known that it’s not working with the MQTT client and Java 11. However, it works with Java 8.
  • In order to support this situation, the platform must be configured accordingly. In case you experience issues please contact product support.
  • If all of the cases above are met and the device connection is still rejected due to certificates validation, then probably some other tenant uploaded a certificate with the same ‘Common Name’ as one of those sent by your device. In this case the device will always try to authorize itself with certificates.

MQTT ClientId

The MQTT ClientId is a field to uniquely identify each connected client. The Cumulocity 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, for example, IMEI, Serial number
defaultTemplateIdentifier NO Check MQTT static templates 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.

Important
The colon character has a special meaning in Cumulocity. Hence, it must not be used in the deviceIdentifier.

Examples of 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 an SSL connection with certificates, the deviceIdentifier must match the ‘Common Name’ of the used certificate (first certificate in the chain, which is provided by the device).

MQTT Quality of Service (QoS)

The Cumulocity 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

Cumulocity requires clean session to be set to “1” (true). Currently we cannot guarantee that disabling clean session will work reliably, hence we recommend you to always enable clean session.

MQTT retained flag

In the current Cumulocity 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 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.

MQTT return codes

When there is an MQTT error, the platform responds with a CONNACK message with a non-zero return code. This message is the first clue that there is a problem. Such a return code can be treated similarly to REST API HTTP codes, such as 401. They can be returned because of an unexpected error, lack of permissions, and so on.

CONNACK is not only a response to a CONNECT message, but also a way to signal errors that occurred in the platform. Therefore, it is possible to receive this message a second time during a normal connection, and without a direct action. It is also a way to signal a closing connection, as most MQTT clients treat CONNACK with a code other than 0 like the connection needs to be closed. See the details below.

The table below shows the list of errors returned by Cumulocity:

Code Canonical message Troubleshooting
0 Connection accepted No issue, connection is working.
1 Connection refused, unacceptable protocol version Unsupported version of the MQTT protocol. Currently, Cumulocity only allows 3.1 and 3.1.1.
2 Connection refused, identifier rejected ClientId is not accepted by the platform.
3 Connection refused, Server unavailable General platform side error, used on internal errors and unknown authorization problems.
Can be received on network issues.
The error should be temporary and independent of device state, therefore the usual solution to this is to try again later.
4 Connection refused, bad username or password Incorrect credentials (wrong username and/or password, but not on empty password). This error is never returned when authenticating with certificates.
5 Connection refused, not authorized Mostly a device side related problem, used when the device doesn’t have permissions or is doing something forbidden. For example, if the client sends malformed messages or tries to execute an operation without authenticating first, such as publishing a message.
Thrown on any issue with certificate authentication (for example, wrong common name, failed auto registration).
Also thrown on general issues with receiving device data or some other authorization problem related to the device state on the platform. For example, device managed object problems, or the sudden removal of permissions. In this situation it may be required to take action on the platform to investigate and apply a fix.
When clientId is too long the user can receive this error when using 3.1 version of MQTT. This can happen if clientId has 24 characters or more.
Lastly, it can also be thrown on unexpected exceptions like performance issues, especially during connection. Therefore it is a good approach to repeat the connection a few times to overcome temporary performance issues.

Refer to MQTT Version 3.1.1 > 3.2 CONNACK - Acknowledge connection request for details on the official MQTT connection return codes.

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.

MQTT broker certificates

MQTT broker uses the certificates which are assigned to the main environment domain. MQTT broker always sends these certificates during TLS handshake to devices. Moreover, Enterprise tenants are not able to customize MQTT broker certificates via the SSL Management feature.

MQTT JWT session token retrieval

The code of the Cumulocity MQTT example client implemented in Java, which connects to the platform using x.509 certificates, is available here: https://github.com/Cumulocity-IoT//cumulocity-examples/tree/develop/mqtt-client. This example client uses the implementation of Eclipse Paho, which is described in detail on their website: https://www.eclipse.org/paho/index.php?page=documentation.php.

Here is an example that shows how to add the needed dependency in Maven to use the Eclipse Paho client:

<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>${paho.version}</version>
</dependency>

Then the instance of the MQTT client can be created with a single line:

MqttClient mqttClient = new MqttClient(BROKER_URL, "d:" + CLIENT_ID, new MemoryPersistence());

The BROKER_URL must contain the protocol, URL and port to which the client will connect, like this: ssl://<cumulocity url>:8883. The CLIENT_ID value must match the value of the common name of the device certificate that will be used. The certificate’s common name should not contain : characters, see MQTT ClientId for more information. The “d:” prefix is used in Cumulocity for device connections and it should not be removed or changed. Now the only thing that must be configured to establish the SSL connection is to fill paths in the code fragment:

sslProperties.put(SSLSocketFactoryFactory.KEYSTORE, getClass().getClassLoader().getResource(KEYSTORE_NAME).getPath());
sslProperties.put(SSLSocketFactoryFactory.KEYSTOREPWD, KEYSTORE_PASSWORD);
sslProperties.put(SSLSocketFactoryFactory.KEYSTORETYPE, KEYSTORE_FORMAT);
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORE, getClass().getClassLoader().getResource(TRUSTSTORE_NAME).getPath());
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTOREPWD, TRUSTSTORE_PASSWORD);
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORETYPE, TRUSTSTORE_FORMAT);
  • The certificate’s common name should not contain : characters, see MQTT ClientId for more information.
  • KEYSTORE_NAME - The path to your keystore which contains the private key and the chain of certificates, which the device uses to authenticate itself.
  • KEYSTORE_PASSWORD - The password created for keystore to use its private key.
  • KEYSTORE_FORMAT - Either “JKS” or “PKCS12” depending on the file format. The path is provided by KEYSTORE_NAME.
  • TRUSTSTORE_NAME - The path to your truststore which contains the certificate of the server.
  • TRUSTSTORE_PASSWORD - The password to access the truststore.
  • TRUSTSTORE_FORMAT - Either “JKS” or “PKCS12” depending on the file format. The path is provided by TRUSTSTORE.

After filling in this data, the example client will use the provided data to connect to the specified platform using certificates. The example also shows how to create the callback for the connection. First thing is to create the class which implements the interface MqttCallbackExtended. Then such a class can be created and an instance of it can be provided to the MQTT client: mqttClient.setCallback(this);.

In general, the MQTT Eclipse Paho client uses the Java Secure Socket Extension, which is part of the Java Development Kit, to provide secure connections via SSL. JSSE provides the Java implementation of the SSL and TLS protocol, which can be configured by developers using its classes. The documentation of the Java Secure Socket Extension shows how the SSL connection is established and provides some examples of customizing the implementation. The full document is available on the official Oracle website.

MQTT examples

Hello MQTT

In this tutorial, you will learn how to use MQTT with Cumulocity using pre-defined messages (called “static templates”).

Prerequisites

In order to follow this tutorial, check the following prerequisites:

  • You have a valid tenant, a user and a password in order to access Cumulocity.
  • You have installed MQTTBox or a similar MQTT tool.
Info
  • The screenshots in the tutorial use MQTTBox. Other tools may look different.
  • If you are using a trial tenant, the default user will not work with this tutorial. Create an additional user instead. The tenant ID and URL data will also differ from trial tenant information.

Configuring the MQTT connection

To configure the MQTT connection, you must pass the following connection parameters (see the screenshot below).

  • MQTT Client Name – Give your client a name to identify it, for example, Cumulocity MQTT.
  • MQTT Client Id – You can use the “Generate a random ID” button (most tools will offer such a button) or provide one yourself. This ID will be linked to your device in Cumulocity. To reconnect to the same device, use the same ID.
  • Protocol – Select the protocol to be used, for example, mqtt/tcp.
  • Host – Provide in the URL your tenant domain, for example, mytenant.cumulocity.com/mqtt.
  • Username – In this case, the username is formed as <tenantID>/<service-user>. You can use the same credentials you use to log into the Cumulocity platform (user alias is not supported). As seen in the example below, for the tenant ID “t76543210” and service user “manga” the username is “t76543210/manga”.
  • Password: The password of the service user.

Cumulocity supports MQTT both via TCP and WebSockets. As URL you can use your tenant domain (for example mytenant.cumulocity.com/mqtt) or the domain of the instance in the format mqtt.<instance_domain> (for example mqtt.cumulocity.com).

Example MQTTBox Configuration

Info
You may review Tenants > Tenant ID and tenant domain in the Cumulocity OpenAPI Specification to get a better understanding between tenant ID and tenant domain.

Other configurations like “clean session” are not important for this example. You can change them to your needs. After clicking Save, you will see a screen similar to the following screenshot.

MQTTBox Established Connection

If there is a blue button on the top bar with a label Not Connected, verify your configuration (especially username and password). If the button is green, you successfully established an MQTT connection to Cumulocity.

Sending data

All MQTT publish messages in this tutorial will be sent to the topic s/us. This is the topic used for Cumulocity’s pre-provided static templates.

MQTTBox Publish Message

Create the device

The first message sent will create our device. Although the static templates support automatic device creation, in this example we will create the device manually. The template 100 will create a new device. It can be used with two optional parameters (deviceName, deviceType).

100,My first MQTT device,c8y_MQTTdevice

Afterwards, you will find this device in the Device Management application as a new device. If you switch to the Identity tab of the device you will notice that there was an identity created automatically to link the device to the MQTT ClientId.

Besides the name and the type, the device does not have more information, so master data must be added.

You can use multiple static templates per publishing separated by a line break (one template per row). This feature is used to set the hardware and the required interval for the device in a single published message.

The hardware can be set with the template 110. It can take 3 parameters (serialNumber, model, revision). Optional parameters in static templates can be left empty if you don’t want to set them. For the hardware all parameters are optional.

The required interval can be set with the template 117 and just takes a single parameter (the interval in minutes).

110,,MQTT test model,1.2.3
117,10

After a reload of the Info page of your device in the Device Management application, you should see the information we just added.

Create measurements

Now the device has some master data and we can start sending some measurements. There are a couple of measurements that can be created directly by using a static template:

  • 210: Signal strength measurement
  • 211: Temperature measurement
  • 212: Battery measurement

The temperature and battery measurement just take the value and time as parameters. For the signal strength, you can pass two values (RSSI and BER).

Passing timestamps in the Cumulocity MQTT implementation is always optional. If you don’t pass them along, the server will automatically create a timestamp with the current server time.

We will make use of this feature in this example. Also, if you do not set the last parameters, you do not need to enter the remaining commas.

210,-87
211,24
212,95

Besides the measurements above, we can also use the template 200 to create a more custom measurement. It will take the measurement fragment, series, value, unit and time as its parameters.

200,myCustomTemperatureMeasurement,fahrenheit,75.2,F

After a reload in the Device Management application, you should see 4 graphs with the newly added measurements in the Measurements tab of your device.

Create alarms

Now we will create some alarms for this device. There are templates to create alarms for the 4 alarm severities:

  • 301: CRITICAL
  • 302: MAJOR
  • 303: MINOR
  • 304: WARNING

Each of them note a type (which is mandatory), a text and a time (both optional).

301,gpio_critical,There is a GPIO alarm
304,simple_warning

The alarm list of your device should now contain one critical alarm and one warning.

Note that we did not set any text for the warning, so it was created with a default alarm text.

Now we will clear the critical alarm again. To achieve this, we use the template 306 which refers to the type of the alarm that should be cleared.

306,gpio_critical

The critical alarm should be cleared afterwards.

Note that you did not have to handle any alarm IDs with the MQTT implementation. Cumulocity will take over this part so that the device communication can be as easy as possible.

Create events

Next, we will create some location events for the device. If you wish, you may use the LatLong website to get the latitude and longitude of your city.

The template 401 lets you create location events and takes latitude, longitude, altitude, accuracy and the time as parameters, but for now we will just use the first two.

401,51.227741,6.773456

In the Device Management application, you can see one event in the event list but the location has not been updated. This is because on REST these are different requests. Instead of the template 401, you can use the template 402 in MQTT. It works exactly the same as 401 but additionally it also updates the position of the device itself.

402,51.227741,6.773456

Now you should see both the Location and the Tracking tab in the device with the Location tab having the same latitude and longitude as the last location event.

Receiving data

So far we have only used MQTT to send data from the client to the server. Now we will send data from the server to the client.

To achieve this, we must first subscribe to the responsible topic. We will do two subscriptions:

  • s/ds : This will subscribe to the static operation templates for the device
  • s/e : This will subscribe to an error topic that can be used for debugging

You can enter both topics after another in the Subscribe field and click Subscribe. The QoS selection does not matter for this example.

Afterwards, your MQTTBox should look like this:

MQTTBox Subscribed Topics

Receive operations

At the current state, the UI does not show any tabs for operations. Up to this point, it was unknown what exactly the device supports, but the list of supported operations can be modified with the template 114. A list of supported operations can be added here.

We will add support for the configuration and shell.

114,c8y_Command,c8y_Configuration

After reloading the UI, the two new tabs will appear (Configuration and Shell).

We can now create a shell command from the UI and click Execute.

In the MQTTBox, you should now have received a new message for the s/ds subscription.

MQTTBox Received Operation

The 511 is indicating what kind of operation we received (in this case c8y_Command). This will be followed by the deviceIdentifier to locate the device with the dedicated operation. This is required if you have a hierarchy with multiple children. In such case, you must know for which of the children the operation was dedicated. Finally, you have the operation specific parameters, which in the case of c8y_Command is only the command text.

After receiving the operation, we can start executing it to initiate the client’s handling the operation. Similar to changing the status of an alarm, you can add the type of operation to the template.

501,c8y_Command

After completing the handling, the operation can be set to successful with the template 503.

Besides the operation type, this operation can also take additional parameters based on what kind of operation it was. We can return a result for the c8y_Command.

503,c8y_Command,Everything went fine
Learning from errors

The topic s/e can help you debugging in case something went wrong. For instance, if we try to send

999,I made this up

we can see a message on the topic because the template 999 is unknown.

40,999,No static template for this message id

Hello MQTT C

In this tutorial, you will learn how to use MQTT client in C with Cumulocity using pre-defined messages (called “static templates”).

Prerequisites

In order to follow this tutorial, check the following prerequisites:

  • You have a valid tenant, a user, and a password in order to access Cumulocity.
  • Verify that you have a gcc compiler installed:
$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  • Download, compile and install the MQTT C Paho Client. You will find more details about Paho on the Paho website.

Developing the “Hello, MQTT world!” client

To develop a very simple “Hello, world!” MQTT client for Cumulocity, you must

  • create the application,
  • build and run the application.
Create the application

Create a source file (for example hello_mqtt.c) with the following content:

#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "MQTTClient.h"

#define ADDRESS     "<<serverUrl>>"
#define CLIENTID    "<<clientId>>"

void publish(MQTTClient client, char* topic, char* payload) {
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    pubmsg.payload = payload;
    pubmsg.payloadlen = strlen(pubmsg.payload);
    pubmsg.qos = 2;
    pubmsg.retained = 0;
    MQTTClient_deliveryToken token;
    MQTTClient_publishMessage(client, topic, &pubmsg, &token);
    MQTTClient_waitForCompletion(client, token, 1000L);
    printf("Message '%s' with delivery token %d delivered\n", payload, token);
}

int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
    char* payload = message->payload;
    printf("Received operation %s\n", payload);
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

int main(int argc, char* argv[]) {
    MQTTClient client;
    MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    conn_opts.username = "<<tenant_ID>>/<<username>>";
    conn_opts.password = "<<password>>";

    MQTTClient_setCallbacks(client, NULL, NULL, on_message, NULL);

    int rc;
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
        printf("Failed to connect, return code %d\n", rc);
        exit(-1);
    }
    //create device
    publish(client, "s/us", "100,C MQTT,c8y_MQTTDevice");
    //set hardware information
    publish(client, "s/us", "110,S123456789,MQTT test model,Rev0.1");
    //listen for operation
    MQTTClient_subscribe(client, "s/ds", 0);

    for (;;) {
        //send temperature measurement
        publish(client, "s/us", "211,25");
        sleep(3);
    }
    MQTTClient_disconnect(client, 1000);
    MQTTClient_destroy(&client);
    return rc;
}

Replace <<clientId>>, <<serverUrl>>, <<tenant_ID>>, <<username>> and <<password>> with your data.

The Cumulocity MQTT protocol supports both unsecured TCP and secured SSL connections (for example tcp://mqtt.cumulocity.com:1883 or ssl://mqtt.cumulocity.com:8883), so as the <<serverUrl>> you can pick the one which fits for you. When using SSL remember to configure MQTTClient_SSLOptions and set it in the MQTTClient_connectOptions.

What does the code in main do?

  • Configure an MQTT connection.
  • Register a on_message callback function which will print incoming messages.
  • Connect with Cumulocity via MQTT protocol.
  • Create a new device with C MQTT name and c8y_MQTTDevice type.
  • Update the device hardware information by putting a "S123456789" serial, a "MQTT test model" model and a "Rev0.1" revision.
  • Subscribe to the static operation templates for the device - this will result in an on_message method call every time a new operation is created.
  • Send temperature measurement every 3 seconds.

What does the code in publish do?

  • Create a new MQTT message and set a payload.
  • Publish message via MQTT protocol.
  • Wait maximum 1 second for a message delivered ACK from the server.

Note that the subscription is established after the device creation, otherwise if there is no device for a given clientId the server will not accept it.

Build and run the application

To build the application, enter

$ gcc hello_mqtt.c -o hello_mqtt -lpaho-mqtt3c

To run the application, enter

$ ./hello_mqtt
Message '100,C MQTT,c8y_MQTTDevice' with delivery token 1 delivered
...

After starting the application, you should see a new device in the Device Management application, listed in All devices.

Additionally, if there will be a new operation created for this device (for example c8y_Restart), information about it will be printed to the console.

Improving the agent

Now that you have done your first step, check out the section Hello MQTT to learn more about Cumulocity MQTT and improve your application.

Hello MQTT Java

In this tutorial, you will learn how to use the Java MQTT client with Cumulocity using pre-defined messages (called “static templates”).

Prerequisites

In order to follow this tutorial, check the following prerequisites:

  • You have a valid tenant, a user and a password in order to access Cumulocity.
  • Verify that you have Maven 3 and at least Java 7 installed.
$ mvn -v
Maven home: /Library/Maven/apache-maven-3.6.0
Java version: 1.8.0_201, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre
Default locale: en_GB, platform encoding: UTF-8
OS name: "mac os x", version: "10.14.2", arch: "x86_64", family: "mac"

Maven can be downloaded from the Maven website.

Developing the “Hello, MQTT world!” client

To develop a very simple “Hello, world!” MQTT client for Cumulocity, you must

  • create a Maven project,
  • add a dependency to the MQTT Java client library to the pom.xml (in this example we will use Paho Java Client),
  • create a Java application,
  • build and run the Java application.
Create a Maven project

To create a plain Java project with Maven, execute the following command:

$ mvn archetype:generate -DgroupId=c8y.example -DartifactId=hello-mqtt-java -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

This will create a folder hello-mqtt-java in the current directory with a skeleton structure for your project.

Add the MQTT Java client library

Edit the pom.xml in the hello-mqtt-java folder. Add a dependency to the MQTT Paho Java Client.

<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>[1.2.1,)</version>
</dependency>

If you are using Java 9 or later, you must set the source and target as described at the Apache Maven Compiler Plugin page, adding the following code:

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>
Create a Java application

Edit the App.java file located in the folder hello-mqtt-java/src/main/java/c8y/example with the following content:

package c8y.example;

import org.eclipse.paho.client.mqttv3.*;
import java.util.concurrent.*;

public class App {

    public static void main(String[] args) throws Exception {

        // client, user and device details
        final String serverUrl   = "tcp://mqtt.cumulocity.com";     /* ssl://mqtt.cumulocity.com:8883 for a secure connection */
        final String clientId    = "my_mqtt_java_client";
        final String device_name = "My Java MQTT device";
        final String tenant      = "<<tenant_ID>>";
        final String username    = "<<username>>";
        final String password    = "<<password>>";

        // MQTT connection options
        final MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName(tenant + "/" + username);
        options.setPassword(password.toCharArray());

        // connect the client to Cumulocity
        final MqttClient client = new MqttClient(serverUrl, clientId, null);
        client.connect(options);

        // register a new device
        client.publish("s/us", ("100," + device_name + ",c8y_MQTTDevice").getBytes(), 2, false);

        // set device's hardware information
        client.publish("s/us", "110,S123456789,MQTT test model,Rev0.1".getBytes(), 2, false);

        // add restart operation
        client.publish("s/us", "114,c8y_Restart".getBytes(), 2, false);

        System.out.println("The device \"" + device_name + "\" has been registered successfully!");

        // listen for operations
        client.subscribe("s/ds", new IMqttMessageListener() {
            public void messageArrived (final String topic, final MqttMessage message) throws Exception {
                final String payload = new String(message.getPayload());

                System.out.println("Received operation " + payload);
                if (payload.startsWith("510")) {
                    // execute the operation in another thread to allow the MQTT client to
                    // finish processing this message and acknowledge receipt to the server
                    Executors.newSingleThreadScheduledExecutor().execute(new Runnable() {
                        public void run() {
                            try {
                                System.out.println("Simulating device restart...");
                                client.publish("s/us", "501,c8y_Restart".getBytes(), 2, false);
                                System.out.println("...restarting...");
                                Thread.sleep(TimeUnit.SECONDS.toMillis(5));
                                client.publish("s/us", "503,c8y_Restart".getBytes(), 2, false);
                                System.out.println("...done...");
                            } catch (MqttException e) {
                                e.printStackTrace();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            }
        });

        // generate a random temperature (10º-20º) measurement and send it every 7 seconds
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Runnable() {
            public void run () {
                try {
                    int temp = (int) (Math.random() * 10 + 10);

                    System.out.println("Sending temperature measurement (" + temp + "º) ...");
                    client.publish("s/us", new MqttMessage(("211," + temp).getBytes()));
                } catch (MqttException e) {
                    e.printStackTrace();
                }
            }
        }, 1, 7, TimeUnit.SECONDS);
    }
}

Replace serverUrl, clientId and device_name as needed. Do not forget to specify the user credentials setting values for tenant_ID, username and password.

Cumulocity MQTT protocol supports both unsecured TCP and secured SSL connections (that is, tcp://mqtt.cumulocity.com:1883 or ssl://mqtt.cumulocity.com:8883), so you can pick the one which fits for you and use it in serverUrl.

What does the code in main do?

  • Configure the MQTT connection.
  • Connect with Cumulocity via a MQTT protocol.
  • Create a new device with a name (device_name) and a type (c8y_MQTTDevice).
  • Update the device hardware information by putting a "S123456789" serial, a "MQTT test model" model and a "Rev0.1" revision.
  • Subscribe to the static operation templates for the device and print all received operations to the console. In case of a c8y_Restart operation, simulate a device restart.
  • Create a new thread which sends temperature measurement every 7 seconds.

Note that the subscription is established after the device creation, otherwise if there is no device for a given clientId, the server will not accept it.

Build and run the application

Use the following commands to build the application:

$ cd hello-mqtt-java
$ mvn clean install
...
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-mqtt-java ---
[INFO] Building jar: /home/schm/Pulpit/hello-mqtt-java/target/hello-mqtt-java-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ hello-mqtt-java ---
[INFO] Installing /home/schm/Pulpit/hello-mqtt-java/target/hello-mqtt-java-1.0-SNAPSHOT.jar to /home/schm/.m2/repository/c8y/example/hello-mqtt-java/1.0-SNAPSHOT/hello-mqtt-java-1.0-SNAPSHOT.jar
[INFO] Installing /home/schm/Pulpit/hello-mqtt-java/pom.xml to /home/schm/.m2/repository/c8y/example/hello-mqtt-java/1.0-SNAPSHOT/hello-mqtt-java-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.642 s
[INFO] Finished at: 2017-03-14T09:16:25+01:00
[INFO] Final Memory: 14M/301M
[INFO] ------------------------------------------------------------------------

and this command to run it:

$ mvn exec:java -Dexec.mainClass="c8y.example.App"
...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building hello-mqtt-java 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ hello-mqtt-java ---
Received operation 510,123456789

After starting the application, you should see a new registered device in the Device Management application, listed in All devices. In the Measurements tab, you will see the temperature measurements being sent by your client.

Additionally, if there will be a new operation created for this device (for example c8y_Restart), information about it will be printed to the console.

Improving the agent

Now that you have done your first step, check out the section Hello MQTT to learn more about Cumulocity MQTT and improve your application.

Hello MQTT Java with certificates

In this tutorial, you will learn how to use the Java MQTT client with Cumulocity using X.509 certificates for authentication.

In the GitHub repository cumulocity-examples, you can find a sample Java MQTT client using X.509 certificates and all necessary scripts used in this tutorial.

Prerequisites

In order to follow this tutorial, check the following prerequisites:

  • You have correctly configured the Java client based on the Hello MQTT Java tutorial.
  • You have a valid tenant, a user and a password in order to access Cumulocity.
  • You have a valid certificate. If you don’t have it, follow the instructions in the next section to generate one.
To generate a valid certificate

If you don’t have a valid certificate, you can generate one for testing purposes, following the instructions below.

  1. Download the scripts from the cumulocity-examples repository.
  2. Create a root self-signed certificate (execute the script 00createRootSelfSignedCertificate.sh) and upload it to your tenant. You can do it via the Device Management application in the UI or via REST.
  3. Create and sign the certificate (execute the script 01createSignedCertificate.sh).
  4. Move the certificates to keystore (execute the script 02moveCertificatesToKeystore.sh). Additionally, if only the device leaf certificate is needed in the keystore, use the –leafonly option.
  5. Finally, import the trusted certificate into keystore running the following command:
$ keytool -importcert -file c8y-mqtt-server.cer -keystore chain-with-private-key-iot-device-0001.jks -alias "Alias"

Developing the “Hello, MQTT world!” client with certificates

To develop a “Hello, world!” MQTT client for Cumulocity with certificates, you must

  • copy the certificate and upload it to the platform,
  • change the configuration in the MQTT client.
To copy and upload the certificate

Copy the certificate from the file chain-iot-device-0001.pem and upload it to the platform employing a POST request:

Endpoint: /tenant/tenants/{tenantId}/trusted-certificates
Authorization: Basic
Content-Type: application/json
Request body:

{
    "status" :  "ENABLED",
    "name" : "sampleName",
    "autoRegistrationEnabled" : "true",
    "certInPemFormat" : "<<certificate in pem format>>"
}
To change the configuration

To change the configuration in the MQTT client, copy the file chain-with-private-key-iot-device-0001.jks into the resource folder and set the configuration. Note that the script employed (Step 4.) uses the password changeit. If you changed the value in the script, also do it for KEYSTORE_PASSWORD and TRUSTSTORE_PASSWORD in the following example.

// Configuration
private static final String KEYSTORE_NAME = "chain-with-private-key-iot-device-0001.jks";
private static final String KEYSTORE_PASSWORD = "changeit";
private static final String KEYSTORE_FORMAT = "jks";

private static final String TRUSTSTORE_NAME = "chain-with-private-key-iot-device-0001.jks";
private static final String TRUSTSTORE_PASSWORD = "changeit";
private static final String TRUSTSTORE_FORMAT = "jks";

private static final String CLIENT_ID = "iotdevice0001";
private static final String BROKER_URL = "<SSL URL of the platform>";

private MqttClient connect() throws MqttException {
    MqttClient mqttClient = new MqttClient(BROKER_URL, "d:" + CLIENT_ID, new MemoryPersistence());
    MqttConnectOptions options = new MqttConnectOptions();

    options.setCleanSession(true);

    Properties sslProperties = new Properties();
    sslProperties.put(SSLSocketFactoryFactory.KEYSTORE, getClass().getClassLoader().getResource(KEYSTORE_NAME).getPath());
    sslProperties.put(SSLSocketFactoryFactory.KEYSTOREPWD, KEYSTORE_PASSWORD);
    sslProperties.put(SSLSocketFactoryFactory.KEYSTORETYPE, KEYSTORE_FORMAT);
    sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORE, getClass().getClassLoader().getResource(TRUSTSTORE_NAME).getPath());
    sslProperties.put(SSLSocketFactoryFactory.TRUSTSTOREPWD, TRUSTSTORE_PASSWORD);
    sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORETYPE, TRUSTSTORE_FORMAT);
    sslProperties.put(SSLSocketFactoryFactory.CLIENTAUTH, true);

    options.setSSLProperties(sslProperties);
    mqttClient.setCallback(this);
    System.out.println("Connecting to the broker at " + BROKER_URL);
    mqttClient.connect(options);

    return mqttClient;
}

The device can now publish and subscribe as a standard device. Note that before the first connect no other actions are required, for example, creating a user. The user is created during the auto registration process.

Info
You do not need to set a password, user or tenant for the MQTT client connecting using certificates. Cumulocity will recognize the tenant and the user by the provided certificate.

Hello MQTT browser-based

In this tutorial, you will learn how to use the browser-based MQTT client with Cumulocity using pre-defined messages (called “static templates”).

Prerequisites

In order to follow this tutorial, check the following prerequisites:

  • You have a valid tenant, a user, and a password in order to access Cumulocity.

Developing the “Hello, MQTT world!” client

To develop a very simple “Hello, world!” MQTT client for Cumulocity, you must

  • create an HTML file and include the MQTT JavaScript client (in this example we will use Paho JavaScript Client),
  • create a JavaScript application,
  • run the application.
Create a JavaScript application

Create an HTML file (for example hello_mqtt_js.html) with the following content:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Hello MQTT World</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js"></script>
    <script src="main.js" defer></script>
</head>
<body>
    <div id="logger"></div>
</body>
</html>

Create a JavaScript file main.js with the following content:

// client, user and device details
var serverUrl   = "ws://mqtt.cumulocity.com/mqtt";     /* wss://mqtt.cumulocity.com/mqtt for a secure connection */
var clientId    = "my_mqtt_js_client";
var device_name = "My JS MQTT device";
var tenant      = "<<tenant_ID>>";
var username    = "<<username>>";
var password    = "<<password>>";

var undeliveredMessages = [];
var temperature = 25;

// configure the client to Cumulocity
var client = new Paho.MQTT.Client(serverUrl, clientId);

// display all incoming messages
client.onMessageArrived = function (message) {
    log('Received operation "' + message.payloadString + '"');
    if (message.payloadString.indexOf("510") == 0) {
        log("Simulating device restart...");
        publish("s/us", "501,c8y_Restart");
        log("...restarting...");
        setTimeout(function() {
            publish("s/us", "503,c8y_Restart");
            log("...done...");
        }, 1000);
    }
};

// display all delivered messages
client.onMessageDelivered = function onMessageDelivered (message) {
    log('Message "' + message.payloadString + '" delivered');
    var undeliveredMessage = undeliveredMessages.pop();
    if (undeliveredMessage.onMessageDeliveredCallback) {
        undeliveredMessage.onMessageDeliveredCallback();
    }
};

function createDevice () {
    // register a new device
    publish("s/us", "100," + device_name + ",c8y_MQTTDevice", function() {
        // set hardware information
        publish("s/us", "110,S123456789,MQTT test model,Rev0.1", function() {
            publish('s/us', '114,c8y_Restart', function() {
                log('Enable restart operation support');
                //listen for operation
                client.subscribe("s/ds");
            })

            // send temperature measurement
            setInterval(function() {
                publish("s/us", '211,'+temperature);
                temperature += 0.5 - Math.random();
            }, 3000);
        });
    });
}

// send a message
function publish (topic, message, onMessageDeliveredCallback) {
    message = new Paho.MQTT.Message(message);
    message.destinationName = topic;
    message.qos = 2;
    undeliveredMessages.push({
        message: message,
        onMessageDeliveredCallback: onMessageDeliveredCallback
    });
    client.send(message);
}

// connect the client to Cumulocity
function init () {
    client.connect({
        userName: tenant + "/" + username,
        password: password,
        onSuccess: createDevice
    });
}

// display all messages on the page
function log (message) {
    document.getElementById('logger').insertAdjacentHTML('beforeend', '<div>' + message + '</div>');
}

init();

Replace serverUrl, clientId and device_name as needed. Do not forget to specify the user credentials setting values for tenant_ID, username and password.

The Cumulocity MQTT protocol supports both unsecured TCP and also secured SSL connections (that is, ws://mqtt.cumulocity.com/mqtt or wss://mqtt.cumulocity.com/mqtt), so you can pick the one which fits for you and use it in serverUrl.

What does the code do?

  • Configure the MQTT connection.
  • Register onMessageArrived callback function which will display all incoming messages. In case of a c8y_Restart operation, simulate a device restart.
  • Register onMessageDelivered callback function which will be called after a publish message has been delivered.
  • After the page is fully loaded, the function init is called and it connects with Cumulocity via a MQTT protocol.
  • When the connection is established, call a createDevice function.
  • Create a new device with a name (device_name) and a type (c8y_MQTTDevice).
  • Update the device hardware information by putting a "S123456789" serial, a "MQTT test model" model and a "Rev0.1" revision.
  • Subscribe to the static operation templates for the device – this will result in onMessageArrived method call every time a new operation is created.
  • Send a temperature measurement every 3 seconds.

Note that the subscription is established after the device creation, otherwise if there is no device for a given clientId, the server will not accept it.

Run the application

Open the hello_mqtt_js.html file in a browser. You should see a new registered device in the Device Management application, listed in All devices. In the Measurements tab, you will see the temperature measurements being sent by your client.

Additionally, if there will be a new operation created for this device (for example c8y_Restart), related information will be displayed in the browser page.

Improving the agent

Now that you have done your first step, check out the section Hello MQTT to learn more about Cumulocity MQTT and improve your application.

Hello MQTT Node.js

In this tutorial, you will learn how to use the Node.js MQTT client with Cumulocity using pre-defined messages (called “static templates”).

Prerequisites

In order to follow this tutorial, check the following prerequisites:

  • You have Node.js and the package manager (npm) installed.
  • You have a valid tenant, a user, and a password in order to access Cumulocity.

Developing the “Hello, MQTT world!” client

To develop a very simple “Hello, world!” MQTT client for Cumulocity, you must

  • create a Node.js application,
  • install the MQTT middleware (in this example we will use the library MQTT.js),
  • run the application.
Create a Node.js application

Create the package.json file to list down the dependencies and other basic information about your application.

{
  "dependencies": {
    "mqtt": "*"
  },
  "scripts": {
    "start": "node app.js"
  }
}

Create the start script (app.js) specified in the package.json file with the following content:

// MQTT dependency https://github.com/mqttjs/MQTT.js
const mqtt = require("mqtt");

// client, user and device details
const serverUrl   = "tcp://mqtt.cumulocity.com";
const clientId    = "my_mqtt_nodejs_client";
const device_name = "My Node.js MQTT device";
const tenant      = "<<tenant_ID>>";
const username    = "<<username>>";
const password    = "<<password>>";

var temperature   = 25;

// connect the client to Cumulocity
const client = mqtt.connect(serverUrl, {
    username: tenant + "/" + username,
    password: password,
    clientId: clientId
});

// once connected...
client.on("connect", function () {
    // ...register a new device with restart operation
    client.publish("s/us", "100," + device_name + ",c8y_MQTTDevice", function() {
        client.publish("s/us", "114,c8y_Restart", function() {
            console.log("Device registered with restart operation support");
        });

        // listen for operations
        client.subscribe("s/ds");

        // send a temperature measurement every 3 seconds
        setInterval(function() {
            console.log("Sending temperature measurement: " + temperature + "º");
            client.publish("s/us", "211," + temperature);
            temperature += 0.5 - Math.random();
        }, 3000);
    });

    console.log("\nUpdating hardware information...");
    client.publish("s/us", "110,S123456789,MQTT test model,Rev0.1");
});

// display all incoming messages
client.on("message", function (topic, message) {
    console.log('Received operation "' + message + '"');
    if (message.toString().indexOf("510") == 0) {
        console.log("Simulating device restart...");
        client.publish("s/us", "501,c8y_Restart");
        console.log("...restarting...");
        setTimeout(function() {
            client.publish("s/us", "503,c8y_Restart");
            console.log("...done...");
        }, 1000);
    }
});

Replace serverUrl, clientId and device_name as needed. Do not forget to specify the user credentials setting values for tenant_ID, username and password.

The Cumulocity MQTT protocol supports both unsecured TCP and secured SSL connections. No matter which connection type you select, your serverUrl should stay the same (like mqtt.cumulocity.com).

What does the code do?

  • Configure the MQTT connection.
  • When the connection is established, register a new device with a name (device_name) and a type (c8y_MQTTDevice).
  • Add restart capabilities to the device.
  • Subscribe to listen for operations.
  • Send a random temperature measurement every 3 seconds.
  • Update the device hardware information by putting a "S123456789" serial, a "MQTT test model" model and a "Rev0.1" revision.
  • Listen to all incoming messages. In case of a c8y_Restart operation, simulate a device restart.

Note that the subscription is established after the device creation, otherwise if there is no device for a given clientId, the server will not accept it.

Run the application

Before running the application, the MQTT middleware must be installed. To achieve this, execute the following command:

$ npm install

Installation needs to be done only once. Afterwards, you only must execute the following command:

$ npm start

You should see a new registered device in the Device Management application, listed in All devices. In the Measurements tab, you will see the temperature measurements being sent by your client.

Additionally, if there will be a new operation created for this device (for example c8y_Restart), related information about it will be printed to the console.

Improving the agent

Now that you have done your first step, check out the section Hello MQTT to learn more about Cumulocity MQTT and improve your application.

Hello MQTT Python

In this tutorial, you will learn how to use the Python MQTT client with Cumulocity using pre-defined messages (called “static templates”).

Prerequisites

In order to follow this tutorial, check the following prerequisites:

  • You have a valid tenant, a user, and a password in order to access Cumulocity.
  • Verify that you have Python 3 installed:
$ python3 --version
Python 3.8.5

Python can be downloaded from www.python.org.

  • Install the Python Paho client using your system’s package manager or using pip:
$ pip install paho-mqtt
Info
The above command installs Paho on your system. You may want to use virtualenv to install it only for this example.
Info
On macOS you may need to execute sudo easy_install pip in case the pip command is not found.

Developing the “Hello, MQTT world!” client

To develop a very simple “Hello, world!” MQTT client for Cumulocity, you must

  • create a Python script,
  • run the script.
Create a Python script

Create a script file (for example hello_mqtt.py) with the following content:

# /usr/bin/env python3
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt
import time, random, threading
import multiprocessing as mp

# client, user and device details
serverUrl   = "mqtt.cumulocity.com"
clientId    = "my_mqtt_python_client"
device_name = "My Python MQTT device"
tenant      = "<<tenant_ID>>"
username    = "<<username>>"
password    = "<<password>>"

# task queue to overcome issue with paho when using multiple threads:
#   https://github.com/eclipse/paho.mqtt.python/issues/354
task_queue = mp.Queue()

# display all incoming messages
def on_message(client, userdata, message):
    payload = message.payload.decode("utf-8")
    print(" < received message " + payload)
    if payload.startswith("510"):
        task_queue.put(perform_restart)

# simulate restart
def perform_restart():
    print("Simulating device restart...")
    publish("s/us", "501,c8y_Restart", wait_for_ack = True);

    print("...restarting...")
    time.sleep(1)

    publish("s/us", "503,c8y_Restart", wait_for_ack = True);
    print("...restart completed")

# send temperature measurement
def send_measurement():
    print("Sending temperature measurement...")
    temperature = random.randint(10, 20)
    publish("s/us", "211,{}".format(temperature))

# publish a message
def publish(topic, message, wait_for_ack = False):
    QoS = 2 if wait_for_ack else 0
    message_info = client.publish(topic, message, QoS)
    if wait_for_ack:
        print(" > awaiting ACK for {}".format(message_info.mid))
        message_info.wait_for_publish()
        print(" < received ACK for {}".format(message_info.mid))

# display all outgoing messages
def on_publish(client, userdata, mid):
    print(" > published message: {}".format(mid))

# main device loop
def device_loop():
    while True:
        task_queue.put(send_measurement)
        time.sleep(7)

# connect the client to Cumulocity and register a device
client = mqtt.Client(clientId)
client.username_pw_set(tenant + "/" + username, password)
client.on_message = on_message
client.on_publish = on_publish

client.connect(serverUrl)
client.loop_start()
publish("s/us", "100," + device_name + ",c8y_MQTTDevice", wait_for_ack = True)
publish("s/us", "110,S123456789,MQTT test model,Rev0.1")
publish("s/us", "114,c8y_Restart")
print("Device registered successfully!")

client.subscribe("s/ds")

device_loop_thread = threading.Thread(target = device_loop)
device_loop_thread.daemon = True
device_loop_thread.start()

# process all tasks on queue
try:
    while True:
        task = task_queue.get()
        task()
except (KeyboardInterrupt, SystemExit):
    print("Received keyboard interrupt, quitting ...")
    exit(0)

Replace serverUrl, clientId and device_name as needed. Do not forget to specify the user credentials setting values for tenant_ID, username and password.

Cumulocity MQTT protocol supports both unsecured TCP and secured SSL connections, so when configuring a port remember to use the correct one. No matter which connection type you select, your serverUrl should stay the same (like mqtt.cumulocity.com).

The above example uses a TCP connection. If you would like to use an SSL connection, remember to use the proper configuration from the Paho MQTT client. Further information can be found at www.eclipse.org.

What does the script do?

  • Configure a MQTT connection.
  • Register an on_message callback function which will print incoming messages. In case of a c8y_Restart operation, it will simulate a device restart.
  • Register an on_publish callback function which will be called after a publish message has been delivered.
  • Connect with Cumulocity via the MQTT protocol.
  • Create a new device with a name (device_name) and a type (c8y_MQTTDevice).
  • Update the device hardware information by putting a "S123456789" serial, a "MQTT test model" model and a "Rev0.1" revision.
  • Subscribe to the static operation templates for the device – this will result in an on_message method call every time a new operation is created.
  • Start the device_loop_thread which sends a temperature measurement every 7 seconds.
  • Prepare a task_queue, used mainly to overcome deadlock issue in Python Paho library. Task queue will run all tasks one by one.

What does the publish message do?

  • Publish a given message about the given topic via MQTT.
  • When publishing the message it uses QoS 2. So to be sure that the message was delivered, it will wait for server ACK (until the on_publish method is called with the matching message ID).

Note that the subscription is established after the device creation, otherwise if there is no device for a given clientId, the server will not accept it.

Run the script

To run the script just use the command:

$ python3 hello_mqtt.py

After starting the application you should see a new registered device in the Device Management application, listed in All devices. In the Measurements tab, you will see the temperature measurements being sent by your client.

Additionally, if there will be a new operation created for this device (for example c8y_Restart), information about it will be printed to the console.

Improving the agent

Now that you have done your first step, check out the section Hello MQTT to learn more about Cumulocity MQTT and improve your application.