This feature is in Public Preview.
That is, it is not yet generally available and may be subject to change in the future.
Requirements
To work with the MQTT Service, the following requirements must be met:
The Cumulocity Messaging Service must be deployed in your Cumulocity environment.
The Cumulocity MQTT Service must be deployed in your Cumulocity environment.
No additional steps are required to enable the MQTT Service for an individual tenant.
The MQTT Service is a new MQTT endpoint implementation for Cumulocity that provides the following benefits:
Sending and receiving arbitrary payloads on any MQTT topic.
Note that the topics used by the Cumulocity Core MQTT implementation currently cannot be used with the MQTT Service.
User-provided microservices can send and receive messages on MQTT topics, and map messages to and from the Cumulocity data model.
The typical use case for such a microservice is to map between MQTT device payloads, and the Cumulocity REST and Notifications 2.0 APIs.
Multi-tenancy support.
A single endpoint serves multiple tenants and tenants are completely isolated from each other.
Bi-directional TLS support.
All MQTT traffic is encrypted and clients can authenticate using X.509 certificates.
The MQTT Service does not replace the existing Core MQTT capability of Cumulocity that supports sending device data already in the Cumulocity domain model directly into the platform.
The new capability provided by the MQTT Service allows for easier integration of MQTT devices that cannot use the Cumulocity domain model.
It also supports more flexible communication patterns between devices, applications, and the Cumulocity platform, controlled by user-provided microservices.
Note that in the public preview, MQTT Service clients within a tenant are not isolated from one another.
That is, an MQTT client can subscribe to topic(s) that another client is publishing on, and receive the messages sent by that client.
Full device isolation will be available in the first General Availability release of the MQTT Service.
This documentation does not describe the basics of MQTT communication.
If you are unfamiliar with MQTT, we recommend you to consult one of the numerous introductions on the internet.
Some references can be found on the MQTT website.
Overview
Architecture
The MQTT Service works together with the Messaging Service to provide a framework for highly customizable and flexible MQTT message processing solutions.
The diagram below illustrates how a message flows, starting from the device, through the Messaging Service,
then to a user-provided microservice where it is converted to the Cumulocity JSON format and
delivered to Cumulocity using the standard REST API.
All MQTT messages published to the MQTT Service are forwarded to the Messaging Service, where they are persisted, waiting to be consumed.
A custom microservice that understands the topic and payload structure can, with the help of the Java Client,
consume the MQTT messages, translate them to the Cumulocity format, and then use the Microservice SDK to push them into Cumulocity.
Similarly, messages can be sent to devices, as shown in the diagram below.
In this case, the user-provided microservice receives messages from Cumulocity through a Notifications 2.0 subscription.
These messages are mapped to the payload structure used by the MQTT devices, then published to MQTT topics using the Java Client.
As with MQTT messages published by devices, messages published from a microservice will be forwarded to the Messaging Service, where they can be consumed by MQTT devices subscribed to the relevant topics.
MQTT Service compared to Core MQTT
The table below presents a basic comparison between the Cumulocity Core MQTT functionality and that of the MQTT Service.
Core MQTT
MQTT Service
QoS
0, 1, 2
0, 1
Clean session
Starting with clean session is recommended
Starting with clean session is required
Retained flag
Not supported
Not supported
Last will
Supported
Supported
MQTT 5.0 features
Not supported
MQTT 5.0 clients can connect. Partial support for MQTT 5.0 features
Authentication
Basic and TLS device certificates
Basic and TLS device certificates
Scalability
Horizontal
Currently a single instance. Horizontal scaling will be available in the GA release
Topic format
Determined by the SmartREST 2.0 protocol
Unrestricted. SmartREST topic names are reserved and cannot currently be used
Payload
Determined by the SmartREST 2.0 protocol
Unrestricted. The maximum message size is 128 KiB including all headers
Extensibility
Limited by SmartREST 2.0 custom templates
Custom mapping microservices can support arbitrary MQTT-based protocols
Message processors/consumers
Built-in message processor for each SmartREST 2.0 topic
Custom mapping microservices can support multiple processors for a topic
JSON via MQTT
Limited feature set
Custom mapping microservices can support arbitrary JSON payloads
MQTT protocol implementation
This section covers some implementation details of the MQTT Service.
The MQTT Service implementation supports clients connecting using MQTT versions 3.1, 3.1.1 and 5.0, although not all MQTT 5.0 protocol features are currently supported.
Connecting to the service
MQTT connections to the MQTT Service must use TCP.
Use your tenant domain as the target host for the connection, for example {my-tenant}.cumulocity.com.
Available ports:
TCP
TLS
9883
no TLS
2883
Port 9883 (TLS) is the default port and should be used for secure, encrypted communication.
Both one-way (server certificate only) and two-way (both client and server certificates) TLS are supported.
When client certificates are not used, the server authenticates the client using standard username and password credentials.
Port 2883 (no TLS) is not enabled in Cumulocity shared public environments due to the security risks of unencrypted traffic.
To enable port 2883 in a dedicated environment, please contact Product support.
Topics
MQTT Service topics are mapped to the Messaging Service subscriptions with identical names, including additional URL encoding.
The Messaging Service subscriptions reliably store the topic messages for asynchronous processing.
The messages stored on these subscriptions can be consumed using a dedicated Java Client.
Topic restrictions
The MQTT Service does not impose any topic structure.
There are just a few topic names which are reserved for historic purposes and future use, namely:
Wildcard topics (+, #) and system topics starting with $ are not currently supported.
Other than these restrictions you are free to use any topic name which is compatible with the MQTT specification.
Topic limits
The MQTT Service imposes several topic-related limits.
See the Service Quotas section for details of the current limits in force.
There is a limit on the total number of topics that a single tenant can create.
When the creation of a new topic, either by creating it via the client publishing a message or subscribing to a non-existent topic, would breach the topic limit the delivery of the packet is prevented.
The different MQTT protocol versions provide different feedback when this limit is exceeded.
MQTT 5 clients:
Have access to the reason code and reason string describing the failure when using QoS 1 with acknowledgements, where the reason code is QUOTA_EXCEEDED: 0x97.
MQTT 3.1 and 3.1.1 clients:
Clients only have access to the reason code describing the failure when using QoS 1 with acknowledgements and only for SUBSCRIBE packets, where the reason code is 0x80.
For PUBLISH packets, the client will be disconnected with no further information as per the MQTT specification.
In addition to the topic count, the MQTT Service also limits the size of the message backlog on each topic.
The message backlog contains all messages that have been published on the topic but not yet received and acknowledged by all subscribers to the topic.
When the backlog limit is reached, further attempts to publish to the topic will fail until some messages have been consumed.
Each message in a topic backlog also has a time-to-live (TTL) that starts at the moment the message is published.
When the TTL of a message expires, that messages will be deleted from the backlog regardless of whether all subscribers have received it or not.
MQTT clients do not receive any notification that messages have been discarded from a backlog due to TTL expiry.
Error topic
The MQTT Service provides clients the ability to review errors through messages received by subscribing to the error topic, $debug/$error.
When subscribing to the topic it will act as a per-client topic, meaning the client will only receive messages exclusively related to their client ID.
For example, if a client was attempting to subscribe to a new topic, and the creation of the topic would exceed the topic limit, only that client would receive an error.
According to the MQTT 3.1.1 specification, if either the server or the client encounters a protocol violation, it must close the network connection on
which it received the control packet which caused the violation.
In such instances MQTT clients must reconnect to be able to receive error messages from the error topic via the subscription.
Error messages received after this reconnection are from the previous session.
This can lead to confusion when attempting corrective actions.
Therefore, we highly recommend you to build a microservice which uses the MQTT Service SDK to consume error messages, or use MQTT 5 for clients and make use of the reason codes feature.
Topic cleanup
The MQTT service will automatically remove topics which are no longer active.
Topics are recognized as inactive when there are no subscriptions and the internal publisher to the topic is closed.
The publisher is responsible for publishing the modified MQTT service messages to the correct topic.
The publishers live within a cache, where the publisher expires after one hour.
Due to this it can take up to an hour after removing all subscriptions from a topic for it to be automatically deleted.
Payload
MQTT protocol messages map bidirectionally to the internal MQTT Service message format which includes the original payload and additional metadata fields.
Assuming Java types, the packed message structure looks as follows:
MqttServiceMessage
Field name
Type
Description
payload
byte[]
MQTT payload
metadata
MqttServiceMetadata
Metadata from the MQTT message
MqttServiceMetadata
Field name
Type
Description
clientId
String
Unique MQTT client identifier, usually used as an external identifier
messageId
int
Unique MQTT message ID per client, available only with QoS 1 and 2
dupFlag
boolean
Indicates this message is a resend by the MQTT client
userProperties
Map
Reserved for future use of MQTT 5.0 features
payloadFormatIndicator
enum
Reserved for future use of MQTT 5.0 features
contentType
String
Reserved for future use of MQTT 5.0 features
correlationData
byte[]
Reserved for future use of MQTT 5.0 features
responseTopic
String
Reserved for future use of MQTT 5.0 features
topic
String
The name of the MQTT topic that the message was published by the client
The Java Client contains classes representing the above model.
Payload restrictions
The MQTT Service does not impose any specific payload format.
All the incoming MQTT messages must meet the specification in terms of fixed and variable headers, but the payload for published messages is unrestricted.
A custom microservice will receive the exact same set of bytes that was sent by an MQTT device, and is responsible for converting these to Cumulocity compatible format.
The size of the MQTT payload is limited to a maximum value that includes both the message header and body.
The size of an MQTT packet header varies, but it will be at least 2 bytes.
See the Service Quotas section for details of the current limit in force.
Features
Authentication and authorization
The authentication types supported by the MQTT Service are:
Username and password: The MQTT username must include the tenant ID and username in the format <tenantID>/<username>.
Device certificates: The MQTT username must include the tenant ID in the format <tenantID>.
ClientId
The MQTT ClientID field identifies the connected client.
ClientID may consist of up to 128 alphanumeric characters.
Each client connecting to the MQTT Service must have a unique client identifier, connecting a second client with the same identifier will result in the previous client’s disconnection.
Quality of Service (QoS)
The MQTT Service implementation supports two levels of MQTT QoS:
QoS 0: At most once:
The client sends the message once (fire and forget).
There is no response from the server.
There is no guarantee that subscribers will receive the message.
QoS 1: At least once:
The client awaits server acknowledgment for each published message.
The client should re-send the message if there was no acknowledgement from the server.
It is guaranteed that subscribers will receive a message that was acknowledged by the server.
Subscribers may receive more than one copy of a message.
QoS 2: Exactly once:
not supported
For subscriptions, the MQTT Service will deliver messages in the QoS that the client defined when subscribing to the topic (QoS 0 or 1).
Clean session
The MQTT Service requires the clean session flag to be set to “1” (true).
Disabling clean session has no effect, meaning that a reconnecting client will not see any messages that it missed since the last disconnection, regardless of how it sets this flag.
Retained flag
The retained flag is currently ignored.
Publishing data with the retained flag on the topic is allowed but has no practical difference to sending it without the flag.
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.
Last will is fully supported by the MQTT Service, and as with with any other publish messages you can use any unreserved topic and any payload.
Return codes
The MQTT Service follows the MQTT specification for server responses.
For example, if invalid credentials are sent in the CONNECT message, the server response CONNACK message contains the 0x05 return code.
The return code can be treated similarly to REST API HTTP codes, such as 401.
MQTT 5.0 features
Clients can connect using version 5.0 of the MQTT protocol.
Support for additional MQTT 5.0 features will be added in future releases.
MQTT TLS certificates
Server certificates
The MQTT Service uses the same server certificates that are assigned to the main Cumulocity environment domain.
It always sends these certificates during TLS handshake to devices.
Moreover, Enterprise tenants are not able to customize those certificates via the SSL Management feature.
Device (client) certificates
Using device certificates with the MQTT Service shares the same requirements as outlined in Device certificates.
Additionally, auto-registration must be enabled when uploading the CA certificate to the platform.
When connecting devices to the MQTT Service using certificates, the tenant ID must be included in the MQTT CONNECT packet in the user name field.
This is required to correctly identify the tenant.
Adding and trusting CA certificate
TLS trust anchors in the Cumulocity platform are defined per tenant.
To use device certificates for authentication, the CA or intermediate certificate that signs the device certificates must be uploaded to the platform and added to the tenant’s list of trusted certificates.
Additionally, the Auto registration field must be enabled when adding certificates.
For detailed instructions on adding and trusting a CA certificate, see Managing trusted certificates.
Creating self-signed certificates
In order to self-sign the device certificates, the root CA certificate needs to be created.
Using the OpenSSL CLI tool, create a private key and then generate a self-signed root certificate from it.
Once the CA certificate has been uploaded and trusted in Cumulocity, devices can authenticate using client certificates signed by your trusted CA.
To connect using any MQTT client, use the previously generated client certificate and key.
This example uses the Mosquitto MQTT client:
Cumulocity uses certificates signed by well-known public CAs.
Some clients (like Mosquitto) require explicitly providing the CA file, while others (like MQTTX) trust these certificates automatically.
Java Client
The MQTT Service Java Client library provides the classes necessary to interact with the MQTT Service.
The following operations are supported by the client:
Publishing messages to the MQTT Service via a WebSocket protocol.
Subscribing to messages from the MQTT Service via a WebSocket protocol
Repositories and dependencies
Follow the Microservice SDK documentation for guidance on how to configure Maven repositories.
To include the MQTT Service Java Client into your project, add the following dependency inside the <dependencies> node:
Example of publishing messages to the MQTT Service via WebSocket:
// Message to be sentfinal String payload = "Hello World";
// Construct a new MqttServiceMessage and set the payloadfinal MqttServiceMessage message = new MqttServiceMessage();
message.setPayload(payload.getBytes());
// Create an instance of MqttServiceApi by specifying the server URI to connect to along with TokenApifinal MqttServiceApi mqttServiceApi = MqttServiceApi.webSocket()
.url(webSocketBaseUrl)
.tokenApi(tokenApi)
.build();
// Build PublisherConfig with topic to which the message is to be sentfinal PublisherConfig config = PublisherConfig.publisherConfig().topic(topic).build();
// Build Publisher and publish MqttServiceMessage. Close the resource either by using a [try-with-resources block](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) as below or by calling publisher.close() explicitlytry (final Publisher publisher = mqttServiceApi.buildPublisher(config)) {
publisher.publish(message);
} catch (Exception e) {
log.error("Could not sent message to {}", topic, e);
}
mqttServiceApi.close();
Example of subscribing to messages from the MQTT Service via WebSocket:
// Create an instance of MqttServiceApi by specifying the server URI to connect to along with TokenApifinal MqttServiceApi mqttServiceApi = MqttServiceApi.webSocket()
.url(webSocketBaseUrl)
.tokenApi(tokenApi)
.build();
// Build SubscriberConfig with topic and subscriber namefinal SubscriberConfig config = SubscriberConfig.subscriberConfig().topic(topic).subscriber(subscriberName).build();
// Build Subscriberfinal Subscriber subscriber = mqttServiceApi.buildSubscriber(config);
// Subscribe by passing implementation of MessageListener to handle messages from the MQTT Service.subscriber.subscribe(new MessageListener() {
@OverridepublicvoidonMessage(MqttServiceMessage message) {
log.info("Message Received: {}", new String(message.getPayload()));
}
});
// Close the resources after usagesubscriber.close();
mqttServiceApi.close();
Frequently Asked Questions
Q: How can I map my MQTT device payloads to Cumulocity without developing a custom microservice?
A: One option is to use the Dynamic Mapping Service for Cumulocity.
This is a community-supported open-source component that allows many different payload formats and encodings to be mapped to the Cumulocity domain model.
Mappings can be configured using a graphical UI or by writing JavaScript code.
Q: How can I obtain device credentials for my MQTT devices?
A: The MQTT Service is not yet integrated with the Cumulocity device bootstrap process.
This support is planned for a future release.
In the meantime, follow the Integration life cycle to bootstrap the device and obtain device credentials.
Once the device credentials are obtained, the device can use them to connect to the MQTT Service.
Q: Does the MQTT Service support the SmartREST 2.0 protocol?
A: Not yet.
Support for SmartREST 2.0 is planned for a future release.
Q: Why does the MQTT Service not use the standard MQTT ports 1883 and 8883?
A: Those ports are already used by Cumulocity Core MQTT.
While both MQTT implementations are operating in parallel, the MQTT Service must use different ports.