RabbitMQ Integration
RabbitMQ Integration connects ThingsBoard to a RabbitMQ broker over AMQP 0-9-1. It reads messages from one or more queues, and an uplink data converter transforms each message into device or asset data, including telemetry and attributes. ThingsBoard can also publish downlink messages to a RabbitMQ exchange.
Use RabbitMQ Integration when:
- Devices, gateways, or backend services already publish data to RabbitMQ.
- One queue carries data for many devices: the converter sets the target device for each message.
- An application must receive ThingsBoard data or commands from a RabbitMQ queue.
Architecture
Section titled “Architecture”- Receive data. A producer publishes a message to an exchange, which routes it to a queue. The integration polls the queue and acknowledges each message as soon as it reads it.
- Decode the payload. The uplink converter identifies the device or asset and extracts attributes and telemetry.
- Process the message. ThingsBoard processes the converted data through the Rule Engine. If Allow create devices or assets is enabled, ThingsBoard can create an entity that does not exist yet.
- Send downlink data (optional). The Rule Engine passes a message to the integration. The downlink converter encodes it, and the integration publishes it to an exchange with the Downlink topic as the routing key.
Prerequisites
Section titled “Prerequisites”- Access to ThingsBoard or ThingsBoard Cloud with integrations enabled for your tenant.
- Permission to create integrations and data converters, and to edit rule chains for downlink.
- A RabbitMQ broker that ThingsBoard reaches on a plain AMQP port,
5672by default. The integration does not support AMQP over TLS. ThingsBoard Cloud accepts only a public broker address. - A broker user with configure, read, and write permissions on the queue’s virtual host.
Set Up RabbitMQ
Section titled “Set Up RabbitMQ”This guide uses a free CloudAMQP instance. With your own broker, create the queue and collect the same values.
Create a CloudAMQP Instance
Section titled “Create a CloudAMQP Instance”- Sign in to CloudAMQP.
- On the Instances page, click + Create New Instance.
- Plan — enter a name, for example
ThingsBoard, keep the free Little Lemur plan, and click Select Region. - Region — choose a data center and a region close to your ThingsBoard server, then click Review. The free plan skips the Configure step.
- Confirm — check the summary and click Create instance.
Open the instance. Its Overview page shows the connection values:
| Value | Example | Source on the Overview page |
|---|---|---|
| Host | hawk.rmq.cloudamqp.com |
Cluster under General |
| Port | 5672 |
Ports under AMQP details |
| Username | llbsoyas |
User & Vhost under AMQP details |
| Virtual host | llbsoyas |
The same User & Vhost value |
| Password | — | Password under AMQP details; click the eye icon to show it |
Create a Queue
Section titled “Create a Queue”- On the CloudAMQP instance Overview page, click RabbitMQ Manager in the upper-left corner. The RabbitMQ Management UI opens in a new tab.
- Go to Queues and Streams. Under Add a new queue, enter
tb-uplinkas the Name, keep Durability set to Durable, and click Add queue. - Check that
tb-uplinkappears in the list in the running state.
The integration also declares its queues when it starts, so it can create a missing queue itself. Create the queue in advance when producers publish before the integration connects: RabbitMQ drops messages routed to a queue that does not exist.
Set Up RabbitMQ Integration
Section titled “Set Up RabbitMQ Integration”Create the uplink converter, assign it to a new RabbitMQ integration, and publish a test message.
Create the Uplink Data Converter
Section titled “Create the Uplink Data Converter”The uplink converter reads the message body and maps it to ThingsBoard entities and data. RabbitMQ Integration uses the Generic converter: the decoder is a TBEL or JavaScript script. For converter types and the full decoder reference, see Uplink data converter.
-
Go to Integrations ⇾ Data converters and click + Add data converter ⇾ Create new converter.
-
Converter type — keep Uplink.
-
Integration type — select RabbitMQ.
-
Name — enter a name, for example
RabbitMQ Uplink Converter. -
Main decoding configuration — the editor opens with the default decoder below. Keep it for JSON messages: it takes the device name and type from
deviceNameanddeviceType, storesserialNumberas an attribute, and stores the other fields as telemetry. The timestamp comes fromts(Unix milliseconds) ortimestamp(ISO 8601); without them, the decoder uses the server time. The editor opens in TBEL; use the TBEL / JS toggle to switch to JavaScript.// Decode an uplink message from a buffer// payload - array of bytes// metadata - key/value object/** Decoder **/// decode payload to JSONvar data = decodeToJson(payload);// --- Device name and type ---var deviceName = data.deviceName != null ? data.deviceName : 'Unknown Device';var deviceType = data.deviceType != null ? data.deviceType : 'default';// var customerName = 'Customer C';// var groupName = 'thermostat devices';// use assetName and assetType instead of deviceName and deviceType// to automatically create assets instead of devices.// var assetName = 'Asset A';// var assetType = 'building';// --- Timestamp parsing ---var timestamp = -1;if (data.ts != null) {timestamp = data.ts;} else if (data.timestamp != null) {timestamp = new Date(data.timestamp).getTime();}if (timestamp == -1) {timestamp = Date.now();}// --- Telemetry and attributes ---var telemetry = {};// Keys from the payload that should be stored as attributes instead of telemetryvar attributeKeyList = ["serialNumber"];// Add the payload keys that match the attribute key list to attributesvar attributes = {};for (var i = 0; i < attributeKeyList.size(); i++) {var attributeKey = attributeKeyList[i];if (data[attributeKey] != null) {attributes[attributeKey] = data[attributeKey];}}// Keys to exclude from telemetry (device info, attributes and non-telemetry fields)var excludeFromTelemetryList = ["deviceName", "deviceType", "ts", "timestamp"];excludeFromTelemetryList.addAll(attributeKeyList);// Parse all remaining JSON fields as telemetrytelemetry.putAll(toFlatMap(data, excludeFromTelemetryList, true));// Result object with device attributes/telemetry datavar result = {deviceName: deviceName,deviceType: deviceType,// customerName: customerName,// groupName: groupName,// assetName: assetName,// assetType: assetType,};// Add attributes to the result only if at least one matching key was foundif (attributes.size() > 0) {result.put("attributes", attributes);}result.put("telemetry", {ts: timestamp,values: telemetry});/** Helper functions 'decodeToString', 'decodeToJson' and 'toFlatMap' are already built-in **/return result;// Decode an uplink message from a buffer// payload - array of bytes// metadata - key/value object/** Decoder **/// decode payload to JSONvar data = decodeToJson(payload);// --- Device name and type ---var deviceName = data.deviceName != null ? data.deviceName : 'Unknown Device';var deviceType = data.deviceType != null ? data.deviceType : 'default';// var customerName = 'Customer C';// var groupName = 'thermostat devices';// use assetName and assetType instead of deviceName and deviceType// to automatically create assets instead of devices.// var assetName = 'Asset A';// var assetType = 'building';// --- Timestamp parsing ---var timestamp = -1;if (data.ts != null) {timestamp = data.ts;} else if (data.timestamp != null) {timestamp = new Date(data.timestamp).getTime();}if (timestamp == -1) {timestamp = Date.now();}// --- Telemetry and attributes ---var telemetry = {};// Keys from the payload that should be stored as attributes instead of telemetryvar attributeKeyList = ["serialNumber"];// Add the payload keys that match the attribute key list to attributesvar attributes = {};for (var i = 0; i < attributeKeyList.length; i++) {var attributeKey = attributeKeyList[i];if (data[attributeKey] != null) {attributes[attributeKey] = data[attributeKey];}}// Keys to exclude from telemetry (device info, attributes and non-telemetry fields)var excludeFromTelemetryList = ["deviceName", "deviceType", "ts", "timestamp"].concat(attributeKeyList);// Parse all remaining JSON fields as telemetrytoFlatMap(data, telemetry, excludeFromTelemetryList);// Result object with device attributes/telemetry datavar result = {deviceName: deviceName,deviceType: deviceType,// customerName: customerName,// groupName: groupName,// assetName: assetName,// assetType: assetType,};// Add attributes to the result only if at least one matching key was foundif (Object.keys(attributes).length > 0) {result.attributes = attributes;}result.telemetry = {ts: timestamp,values: telemetry};/** Helper functions **/function decodeToString(payload) {return String.fromCharCode.apply(String, payload);}function decodeToJson(payload) {var str = decodeToString(payload);return JSON.parse(str);}function toFlatMap(obj, result, excludeList, prefix) {prefix = prefix || '';for (var key in obj) {if (excludeList.indexOf(key) !== -1) continue;var value = obj[key];var fullKey = prefix ? prefix + '.' + key : key;if (typeof value === 'object' && value !== null && !Array.isArray(value)) {toFlatMap(value, result, excludeList, fullKey);} else {result[fullKey] = value;}}}return result;To adapt:
- Device name in another field — replace
data.deviceName, for example withdata.id. - Other attributes — add keys to
attributeKeyList, for example"firmwareVersion". - Assets instead of devices — uncomment
assetNameandassetType, and use them in the result instead ofdeviceNameanddeviceType. - Customer or group — uncomment
customerNameorgroupNameand add it to the result. - Plain-text payload — read it with
decodeToString(payload)and parse the text instead of callingdecodeToJson.
- Device name in another field — replace
-
Click Test decoder function and check the result (see Test the Decoder).
-
Click Add.
Decoder Inputs
The decoder signature is function decoder(payload, metadata): object | object[].
| Variable | Type | Content |
|---|---|---|
payload |
byte array | The message body. The integration reads it as UTF-8 text, so send JSON or text: binary data does not arrive intact. |
metadata |
{[key: string]: string} |
integrationName and the key–value pairs from the integration’s Metadata field. Message headers, properties, and the routing key are not passed. |
Built-in helpers:
| Function | Result |
|---|---|
decodeToJson(payload) |
Parses the bytes as JSON and returns an object. |
decodeToString(payload) |
Converts the bytes to a UTF-8 string. |
toFlatMap(obj, excludeKeys, flatNested) |
TBEL only. Returns a flat key–value map of obj, skipping excludeKeys. With flatNested set to true, nested objects become dot-separated keys. The JavaScript template defines its own toFlatMap(obj, result, excludeList), which writes into result. |
For field renaming, nested values, and non-JSON payloads, see Common scripting patterns.
Test the Decoder
Click Test decoder function below the editor. The dialog opens with Payload content type set to JSON and this sample payload:
{ "deviceName": "Thermometer", "deviceType": "thermostat", "serialNumber": "SN-12345", "temperature": 25.5}Click Test. The Output panel shows:
{ "deviceName": "Thermometer", "deviceType": "thermostat", "attributes": { "serialNumber": "SN-12345" }, "telemetry": { "ts": 1791807972006, "values": { "temperature": 25.5 } }}ts is the current time, because the payload has neither ts nor timestamp. Check that deviceName is set and telemetry.values holds the expected keys. If the output is empty or shows an error, fix the decoder and test again.
Create the Integration
Section titled “Create the Integration”- Go to Integrations ⇾ Integrations and click + Add integration.
- Basic settings:
- Integration type — select RabbitMQ.
- Name — keep the default
RabbitMQ integrationor enter your own. - Enable integration and Allow create devices or assets — keep both on, so the device is created on its first uplink.
- Click Next.
- Uplink data converter:
- Click Select existing and choose
RabbitMQ Uplink Converter. - Alternatively, click Create new to write a decoder here.
- Click Next.
- Click Select existing and choose
- Downlink data converter:
- Click Skip. Add a downlink converter later if you need to publish data to RabbitMQ.
- Connection:
- Host — enter the CloudAMQP Cluster hostname, for example
hawk.rmq.cloudamqp.com. - Port — keep
5672. - Queue — set Name to
tb-uplink. Turn Durable on, and turn Exclusive and Auto delete off, to match the queue you created. - Advanced settings — expand it and enter the Username, Password, and Virtual host from the instance Overview page (see Create a CloudAMQP Instance).
- Leave the other parameters at their defaults. See Connection Settings for details.
- Host — enter the CloudAMQP Cluster hostname, for example
- Optionally, click Check connection. ThingsBoard connects to the broker and shows the result. The check covers the host, port, credentials, and virtual host, not the queue.
- Click Add.
Connection Settings
Section titled “Connection Settings”| Parameter | Default | Description |
|---|---|---|
| Host | — | Broker hostname or IP address. ThingsBoard Cloud accepts only a public address. |
| Port | 5672 |
Plain AMQP port. The integration does not use TLS. |
| Queue ⇾ Name | my-queue |
Queue to read from. To read several queues, separate their names with commas and no spaces, for example tb-uplink,tb-status. |
| Queue ⇾ Durable | Off | The queue survives a broker restart. |
| Queue ⇾ Exclusive | On | The queue belongs to the integration’s connection, and RabbitMQ deletes it when the connection closes. |
| Queue ⇾ Auto delete | On | RabbitMQ deletes the queue after its last consumer unsubscribes. |
| Execute remotely | Off | Runs the integration as a separate process outside the ThingsBoard cluster, for example next to a broker in a private network. ThingsBoard generates an Integration key and Integration secret for it. See Remote Integration. |
Advanced settings
| Parameter | Default | Description |
|---|---|---|
| Username | — | Broker user. If empty, the client uses guest, which RabbitMQ accepts only from localhost. |
| Password | — | Password of the broker user. |
| Downlink topic | — | Routing key of downlink messages. See Configure Downlink. |
| Exchange name | — | Exchange that receives downlink messages. If empty, ThingsBoard uses the default exchange, which routes each message to the queue named by the routing key. |
| Virtual host | — | Virtual host of the queue. If empty, the broker uses /. |
| Connection timeout, ms | 60000 |
Time to establish the TCP connection. |
| Handshake timeout, ms | 10000 |
Time to complete the AMQP handshake. |
| Poll interval, ms | 5000 |
Pause before the next poll after the integration finds its queues empty. While messages are available, it reads them without a pause. Values below 200 count as 200. |
| Description | — | Free-text description. |
| Metadata | — | Key–value pairs added to the metadata of every message from this integration. |
After a network failure, the integration reconnects to the broker automatically.
Test Uplink
Section titled “Test Uplink”Publish a test message to the queue, then confirm that ThingsBoard decoded it and created the device.
Send a Test Uplink
Section titled “Send a Test Uplink”-
In the RabbitMQ management UI, go to Queues and Streams and click the
tb-uplinkqueue. -
Expand Publish message and paste the payload into Payload. Leave the other fields at their defaults.
{"deviceName": "Thermometer-01","deviceType": "thermostat","temperature": 23.5,"humidity": 60} -
Click Publish message. The page shows Message published.
CloudAMQP exposes the RabbitMQ management HTTP API on port 443. Replace USER, PASSWORD, HOST, and VHOST with the values from the instance Overview page:
curl --user USER:PASSWORD \ --json '{ "properties": {"content_type": "application/json"}, "routing_key": "tb-uplink", "payload": "{\"deviceName\":\"Thermometer-01\",\"deviceType\":\"thermostat\",\"temperature\":23.5,\"humidity\":60}", "payload_encoding": "string" }' \ "https://HOST/api/exchanges/VHOST/amq.default/publish"The response {"routed":true} confirms that the message reached the queue.
Verify the Result
Section titled “Verify the Result”- Integration events — go to Integrations ⇾ Integrations, open the integration, and click the Events tab. The uplink appears with status OK. Click
⋅⋅⋅in the Message column to see the message body. - Converter events — open
RabbitMQ Uplink Converterin Integrations ⇾ Data converters and click the Events tab. In shows the message body, Out shows the decoded result, and Metadata shows the integration name. - Device — go to Devices & assets ⇾ Devices. The integration has created Thermometer-01 with the
thermostatprofile. Open it and checktemperatureandhumidityon the Latest telemetry tab.
Configure Downlink
Section titled “Configure Downlink”ThingsBoard publishes a downlink when the Rule Engine routes a message to the integration — for example, after a shared attribute update. The integration publishes the encoder’s data to the Exchange name exchange with the Downlink topic as the routing key. With an empty Exchange name, the default exchange delivers the message to the queue whose name equals the Downlink topic.
The message carries no properties: no headers, no content type, and transient delivery. The integration ignores the encoder’s metadata.
The downlink converter turns a Rule Engine message into the published payload. For the full encoder reference, see Downlink data converter.
Create the Downlink Queue
Section titled “Create the Downlink Queue”- On the CloudAMQP instance Overview page, click RabbitMQ Manager in the upper-left corner. The RabbitMQ Management UI opens in a new tab.
- Go to Queues and Streams and expand Add a new queue.
- Enter
tb-downlinkas the Name, keep Durability set to Durable, and click Add queue.
Create and Assign the Downlink Converter
Section titled “Create and Assign the Downlink Converter”Add a downlink converter to the integration and set the Downlink topic, the queue that receives downlinks.
- Open the integration in Integrations ⇾ Integrations and click Toggle edit mode (pencil icon).
- In the Downlink data converter field, click Create new. The Downlink converter type and RabbitMQ integration type are preselected.
- Enter a name, for example
RabbitMQ Downlink Converter. - In Main encoding configuration, replace the default encoder with the encoder below.
- To record downlink events, click the debug icon next to the name, select All messages, and click Apply.
- Click Add.
- Advanced settings — expand it and set the downlink queue:
- Downlink topic — enter
tb-downlink. The field is empty by default, and with an empty value RabbitMQ drops every downlink without an error. - Exchange name — leave empty.
- Downlink topic — enter
- Click Apply changes.
Encoder used in this guide (TBEL and JavaScript):
/** Encoder **/
// Publish the message data as is.var result = { // Payload content type: JSON, TEXT, or BINARY (Base64). contentType: "JSON", data: JSON.stringify(msg), // The integration does not use the downlink metadata. metadata: {}};
return result;To adapt:
- Selected fields — build
datafrom the fields you need, for exampleJSON.stringify({ interval: msg.temperatureUploadFrequency }). - Binary payload — set
contentTypetoBINARYand return the bytes indataas a Base64 string. - Other message types — branch on
msgType, for exampleRPC_CALL_FROM_SERVER_TO_DEVICE. See Rule Engine message types.
Configure the Root Rule Chain
Section titled “Configure the Root Rule Chain”- Go to Data processing ⇾ Rule chains and open the Root Rule Chain.
- From the Action section, drag an integration downlink node onto the canvas.
- Enter a Name (for example,
Downlink to RabbitMQ), select your RabbitMQ integration, and click Add. - Connect the message type switch node to the integration downlink node with the Attributes Updated relation.
- Click Apply changes.
Test Downlink
Section titled “Test Downlink”- Go to Devices & assets ⇾ Devices, select Thermometer-01, and open the Attributes tab.
- Select Shared attributes and click +.
- Set Key to
temperatureUploadFrequency, Type to Integer, Value to60, and click Add. ThingsBoard publishes the downlink.
Verify the Downlink
Section titled “Verify the Downlink”- RabbitMQ — in the management UI, open the
tb-downlinkqueue and expand Get messages. Set Ack Mode to Nack message requeue true, so the message stays in the queue, and click Get Message(s). The result shows Exchange(AMQP default), Routing Keytb-downlink, and Payload{"temperatureUploadFrequency":60}. - Converter events — open the downlink converter’s Events tab. In shows the Rule Engine message, and Out shows the encoded payload.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Fix |
|---|---|---|
| Integration does not start; Check connection fails | Wrong Host or Port, or the broker is unreachable. | Check that ThingsBoard reaches host:5672. A TLS-only port such as 5671 does not work. |
| Same, after the TCP connection | Wrong Username, Password, or Virtual host. | Copy them from the broker again. On CloudAMQP, the virtual host equals the username. |
Host must be in the public network. |
The host is a private address, and ThingsBoard Cloud blocks it. | Use a public broker, or run the integration with Execute remotely. |
Failed to bind queue: [...] |
The queue exists with other Durable, Exclusive, or Auto delete flags, or the user lacks the configure permission. | Match the flags to the queue in the management UI, or grant the permission. |
| Queue disappears after a restart | Exclusive or Auto delete is on. | Turn both off and turn Durable on. |
| No uplinks arrive | The producer routes messages to another queue, or a queue name contains a space. | Check the bindings in the management UI. Separate queue names with commas only. |
| Converter error; the message is gone | The body is not valid JSON, or the decoder fails on it. The integration has already acknowledged the message. | Check In and Error in the converter events, fix the decoder, and publish again. |
| Device not created | deviceName is empty, or Allow create devices or assets is off. |
Check Out in the converter events and the integration settings. |
| Downlink event is OK, but the queue is empty | Downlink topic is empty, or it does not match a queue name or binding. | With an empty Exchange name, set Downlink topic to the queue name. |
| No downlink event | No downlink converter is assigned, or the rule chain does not reach the integration downlink node. | Check the integration settings and the Attributes Updated relation. |
To read debug events, open the integration or converter, click Events, and select an event: In is the received data, Out is the converter result, and Error holds the error text.
See Also
Section titled “See Also”- Integrations overview — how integrations, converters, uplinks, and downlinks fit together.
- Uplink data converter — decoder inputs, output format, and scripting patterns.
- Downlink data converter — encoder reference.
- RabbitMQ node — publish messages from the Rule Engine without an integration.
- Remote Integration — run the integration outside the ThingsBoard cluster.
- TBEL — built-in functions and syntax for converter scripts.
- RabbitMQ queues — queue properties, durability, and exclusivity.
Was this helpful?