Skip to content
Stand with Ukraine flag

SODAQ Universal Tracker with T-Mobile NB-IoT and ThingsBoard

SODAQ NB-IoT Trackers collect GPS location and sensor data and transmit it over the T-Mobile NB-IoT network. This guide walks through connecting a SODAQ NB-IoT Tracker to ThingsBoard PE using the T-Mobile IoT CDP integration, setting up a data converter, importing alarm rule chains, and visualizing data on a dashboard.

SODAQ tracker dashboard demo

The uplink data converter decodes the incoming hex-encoded payload from T-Mobile NB-IoT into the ThingsBoard telemetry format.

Input payload from T-Mobile NB-IoT platform:

{
"reports": [{
"serialNumber": "IMEI:0123456789",
"timestamp": 1547035621977,
"subscriptionId": "43524b52-b924-40f0-91f0-e7fa71dca87b",
"resourcePath": "uplinkMsg/0/data",
"value": "010145292a2bfbfc0000000000000000e6e3355c751a879de31e6535d10306005600d00402"
}]
}

Decoded output:

{
"deviceName": "0123456789",
"deviceType": "tracker",
"telemetry": [{
"ts": 1547035622000,
"values": {
"batteryVoltage": 4.17,
"temperature": 26,
"latitude": 51.8233479,
"longitude": 6.4042341,
"altitude": 6,
"speed": 86,
"satellitesObserved": 208,
"timetToFirstFix": 4
}
}]
}

Key points:

  • The IMEI from the incoming message becomes the device name in ThingsBoard.
  • ThingsBoard automatically creates a device with type tracker and a name equal to the IMEI.
  • Timestamp and sensor readings are decoded from the incoming hex string.

The following table shows each encoded field’s position and byte length in the hex string:

FieldFirst byteByte length
ts164
batteryVoltage201
temperature211
latitude224
longitude264
altitude302
speed322
satellitesObserved351
timetToFirstFix361
  1. Download sodaq_uplink_data_converter.json.
  2. Go to Integrations center ⇾ Data converters and click + Add data converter > Import converter.
  3. Drag and drop the downloaded sodaq_uplink_data_converter.json file.
  4. Click Import.

Decoder function:

// Decode an uplink message from a buffer
// payload - array of bytes
// metadata - key/value object
/** Decoder **/
// decode payload to JSON
var data = decodeToJson(payload);
var reports = data.reports;
var deviceName = data.devName;
// Result object
var result = {
deviceName: {},
deviceType: "tracker",
telemetry: []
};
for (var i = 0; i < reports.length; i++) {
result.deviceName = reports[i].serialNumber.replace("IMEI:", "");
var telemetryObj = {
ts: {},
values: {}
};
var timestamp = stringToInt(reports[i].value.substring(32, 40)) * 1000;
var v = stringToInt(reports[i].value.substring(40, 42)) / 100 + 3;
var t = stringToInt(reports[i].value.substring(42, 44));
var lat = stringToInt(reports[i].value.substring(44, 52)) / 10000000;
var lon = stringToInt(reports[i].value.substring(52, 60)) / 10000000;
var alt = stringToInt(reports[i].value.substring(60, 64));
var speed = stringToInt(reports[i].value.substring(64, 68));
var sat = stringToInt(reports[i].value.substring(68, 70));
var ttf = stringToInt(reports[i].value.substring(70, 72));
telemetryObj.ts = timestamp;
telemetryObj.values.batteryVoltage = v;
telemetryObj.values.temperature = t;
if (lat !== 0) {
telemetryObj.values.latitude = lat;
}
if (lon !== 0) {
telemetryObj.values.longitude = lon;
}
if (alt !== 0) {
telemetryObj.values.altitude = alt;
}
telemetryObj.values.speed = speed;
telemetryObj.values.satellitesObserved = sat;
telemetryObj.values.timetToFirstFix = ttf;
result.telemetry.push(telemetryObj);
}
/** Helper functions **/
function stringToInt(hex) {
return parseInt('0x' + hex.match(/../g).reverse().join(''));
}
function decodeToString(payload) {
return String.fromCharCode.apply(String, payload);
}
function decodeToJson(payload) {
var str = decodeToString(payload);
return JSON.parse(str);
}
return result;
  1. Go to Integrations center ⇾ Integrations and click + Add integration.
  2. Basic settings:
    • Set Integration type to iotcreators.com (T-Mobile – IoT CDP).
    • Enable integration and Allow create devices or assets are on by default.
    • Click Next.
  3. Uplink data converter:
    • Select existing — choose the previously created SODAQ Uplink data converter from the list.
    • Click Next.
  4. Connection:
    • Base URL is pre-filled with your ThingsBoard instance URL.
    • Copy the generated HTTP export URL — you will configure IoT Creators to POST to this address.
    • Click Add to save the integration.

For more information about MQTT integrations in ThingsBoard, see the IoT Creators integration documentation.

Step 3. Post telemetry and verify the integration

Section titled “Step 3. Post telemetry and verify the integration”

Before configuring the T-Mobile platform, verify that ThingsBoard is correctly configured by sending a test message with cURL.

  1. Download the test data file: telemetry-data.json.

  2. Run the following command, replacing $HTTP_ENDPOINT_URL with the copied endpoint URL from the integration:

    Terminal window
    curl -v -X POST -d @telemetry-data.json $HTTP_ENDPOINT_URL --header "Content-Type:application/json"

A new device should be created in ThingsBoard:

Go to Entities ⇾ Devices — device 0123456789 is provisioned automatically on the first uplink. Open the Latest telemetry tab to verify decoded data such as location, battery voltage, and other sensor values.

Step 4. T-Mobile NB-IoT platform callback configuration

Section titled “Step 4. T-Mobile NB-IoT platform callback configuration”

In the T-Mobile IoT CDP platform, configure the callback URL to the HTTP endpoint URL from Step 2. Use the image below as a reference:

To trace the message through the integration, go to Integrations center ⇾ Integrations, click iotcreators.com (T-Mobile – IoT CDP) integration, open the Events tab, and set Event type to Debug. Click in the Message column to see the reports received by the integration.

This guide uses a modified Root Rule Chain and a new Tracker Alarms rule chain. The rule chain forwards telemetry to the Tracker Alarms chain, which evaluates individual alarm threshold parameters configured in the dashboard.

Download and import the Tracker Alarms rule chain: tracker-alarms.json.

Download sodaq-dashboard.json and import it in Dashboards. See the dashboard import instructions.

After importing the dashboard, navigate to the Tracker details state and set the alarm threshold values:

  • Max Speed
  • Min Voltage
  • Min Temperature
  • Max Temperature

Once the rule chains and dashboard are configured, trigger the device to post real data and verify that the integration and rule chains work as expected.

The following sections explain how the rule chains work and how to recreate them from scratch. These steps are optional — beginners can skip this section.

You can add additional HTTP headers with unique parameters to secure the integration. Add a custom header (like MY-INTEGRATION-AUTH-HEADER with a random string value) to both the integration configuration (Step 2) and the T-Mobile platform configuration (Step 4). The header values must match for data to flow correctly.

The Tracker Alarms rule chain uses the following nodes:

  • Node A: Originator attributes — adds Message Originator Attributes (client, shared, and server scope) and the latest telemetry values into message metadata.
  • Nodes B, C, D, E: Filter Script — evaluate threshold conditions. Return true if the condition is met, false otherwise.
  • Nodes F, H, J, L: Create alarm — create or update an alarm when the corresponding filter script returns true.
  • Nodes G, I, K, M: Clear alarm — clear the alarm when the corresponding filter script returns false.
  • Node O: Rule Chain — forwards incoming messages to the Tracker Alarms rule chain.
  1. Go to Rule Chains → Add new Rule Chain. Enter the name Tracker Alarms and click Add.

  2. Open the rule chain and click Edit. Add 13 nodes as described below.

  3. Add Node A: Originator attributes and connect it to the Input node. This node fetches shared scope attributes set from the dashboard.

    Configure it with the following shared attributes: maxTemperature, minTemperature, maxSpeed, minVoltage. Set the name to Fetch Limit telemetry.

  4. Add four Filter Script nodes (B, C, D, E) and connect each to Node A with relation type Success:

    NodeNameScript
    BValidate Max temperaturereturn msg.temperature > metadata.shared_maxTemperature;
    CValidate Min temperaturereturn msg.temperature < metadata.shared_minTemperature;
    DValidate Max speedreturn msg.speed > metadata.shared_maxSpeed;
    EValidate Min voltagereturn msg.batteryVoltage < metadata.shared_minVoltage;
  5. Add four Create alarm nodes (F, H, J, L) and connect each to the corresponding Filter Script node with relation type True:

    NodeNameAlarm typeDetails function
    FMax TemperatureMax Temperaturevar details = {}; details.value = msg.temperature; if (metadata.prevAlarmDetails) { details = JSON.parse(metadata.prevAlarmDetails); } return details;
    HMin temperatureMin temperaturevar details = {}; details.value = msg.temperature; if (metadata.prevAlarmDetails) { details = JSON.parse(metadata.prevAlarmDetails); } return details;
    JMax SpeedMax Speedvar details = {}; details.value = msg.speed; if (metadata.prevAlarmDetails) { details = JSON.parse(metadata.prevAlarmDetails); } return details;
    LMin VoltageMin Voltagevar details = {}; details.value = msg.batteryVoltage; if (metadata.prevAlarmDetails) { details = JSON.parse(metadata.prevAlarmDetails); } return details;
  6. Add four Clear alarm nodes (G, I, K, M) and connect each to the corresponding Filter Script node with relation type False:

    NodeNameAlarm typeDetails function
    GClear Max TemperatureMax Temperaturevar details = {}; if (metadata.prevAlarmDetails) { details = JSON.parse(metadata.prevAlarmDetails); } details.clearedValue = msg.temperature; return details;
    IClear Min temperatureMin temperaturevar details = {}; if (metadata.prevAlarmDetails) { details = JSON.parse(metadata.prevAlarmDetails); } details.clearedValue = msg.temperature; return details;
    KClear Max SpeedMax Speedvar details = {}; if (metadata.prevAlarmDetails) { details = JSON.parse(metadata.prevAlarmDetails); } details.clearedValue = msg.speed; return details;
    MClear Min VoltageMin Voltagevar details = {}; if (metadata.prevAlarmDetails) { details = JSON.parse(metadata.prevAlarmDetails); } details.clearedValue = msg.batteryVoltage; return details;
  7. The completed Tracker Alarms rule chain:

Add two nodes to the existing Root Rule Chain:

  1. Add a Filter Script node and connect it to the Save Timeseries node with relation type Success. Set the name to Tracker filter and enter the following script:

    return metadata.deviceType === 'tracker';
  2. Add a Rule Chain node and connect it to the Filter Script node with relation type True. Set the name to Tracker Alarms and point it to the Tracker Alarms rule chain.

  3. The completed Root Rule Chain: