Skip to content
© 2026 The ThingsBoard Authors
Try for free

ThingsBoard Cloud

Choose your data region

Your data stays in the region you choose, for residency and compliance. No credit card required.

Rather run it yourself? Install on your own servers

Two-way RPC over MQTT

This recipe extends the One-way RPC over MQTT setup with a device acknowledgement: ThingsBoard sends a command via the downlink converter, the device processes it and publishes a response back, and the uplink converter stores that response as telemetry.

Modify the converters to use a dedicated topic pair for two-way RPC:

  • Downlink: publish to tb/mqtt-integration-tutorial/fridge/+/rx/twoway
  • Uplink: subscribe to tb/mqtt-integration-tutorial/fridge/+/rx/response for device responses
  • Complete the One-way RPC over MQTT recipe — this tutorial modifies the converters and integration created there.
  • The device simulator (Python 3) — handles the subscribe/respond cycle automatically.

Update the uplink converter to store both incoming temperature readings and device RPC responses as telemetry:

  1. Go to Integrations ⇾ Integrations and open the MQTT integration.
  2. Click Toggle edit mode.
  3. In the Uplink data converter field, click Edit data converter.
  4. Update the decoder script.

    /** Decoder **/
    // decode payload to string
    var payloadStr = decodeToString(payload);
    var data = JSON.parse(payloadStr);
    var deviceName = metadata.topic.split("/")[3];
    // decode payload to JSON
    var deviceType = 'sensor';
    // Result object with device attributes/telemetry data
    var telemetry = data;
    var result = {
    deviceName: deviceName,
    deviceType: deviceType,
  5. Click Save.

Update the downlink converter to publish RPC commands to the /rx/twoway topic:

  1. In the Downlink data converter field, click Edit data converter.
  2. Update the encoder script.

    /** Encoder **/
    var value = parseFloat(msg.params);
    var data = {value: value};
    var result = {
    contentType: "JSON",
    data: JSON.stringify(data),
    metadata: {
    topic: 'tb/mqtt-integration-tutorial/fridge/' + metadata['deviceName'] + '/rx/twoway'
    }
    };
    return result;
  3. Click Save.

The integration must subscribe to the device response topic so that replies are processed by the uplink converter:

  1. In the Topic filters section, click Add topic filter.

  2. Enter the response topic filter:

    Terminal window
    tb/mqtt-integration-tutorial/fridge/+/rx/response
  3. Apply all changes.

mosquitto_pub/mosquitto_sub cannot handle the subscribe-then-respond pattern required for two-way RPC. Use the Python device emulator instead — it subscribes to the twoway topic, processes each incoming command, and automatically publishes a response back to the response topic.

  1. Download the device simulator.
  2. Run the emulator:

    Terminal window
    python3 thingsboard_mqtt_emulator.py

Open the MQTT RPC dashboard and turn the knob. The emulator terminal will output:

Terminal window
Topic: tb/mqtt-integration-tutorial/fridge/SN-001/rx/twoway
Message: {"value":-6.0}
This is a Two-way RPC call. Going to reply now!
Sending a response message: {"targetTemperature": -6.0}
Sent a response message: {"targetTemperature": -6.0}

Go to Devices & assets ⇾ Devices, open SN-001, and check the Latest telemetry tab. The device response is stored as targetTemperature telemetry alongside the regular temperature readings.

This pattern implements an application-level two-way RPC using separate topics — it is distinct from ThingsBoard’s native device request-response mechanism. At the Rule Engine level the message still carries oneway: true (set automatically by the Knob Control widget); ThingsBoard does not block waiting for a reply.

The full cycle:

  1. Knob turn ⇾ RPC_CALL_FROM_SERVER_TO_DEVICE ⇾ Rule Engine ⇾ Integration Downlink node ⇾ downlink converter ⇾ MQTT PUBLISH to .../rx/twoway
  2. The device emulator receives the command, extracts the value, and publishes {"targetTemperature": <value>} to .../rx/response
  3. The MQTT integration (subscribed to /rx/response via the topic filter added in Step 3) receives the response as a new uplink ⇾ uplink converter stores the full JSON payload as device telemetry

The /rx/response topic is kept separate from the command topic so the uplink converter can store device acknowledgements independently of regular sensor telemetry. Any key-value pair in the response payload (e.g. targetTemperature) becomes a telemetry entry on the SN-001 device.

Unlike native ThingsBoard two-way RPC (used with the MQTT Device API), this approach requires no request ID correlation — the device echoes back the applied value directly, and the response is simply stored as telemetry.