Skip to content
Stand with Ukraine flag

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 center ⇾ 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,
    attributes: {
    integrationName: metadata['integrationName'],
    },
    telemetry: telemetry
    };
    /** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/
    return result;
  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 Entities → 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.