ThingPark Integration
ThingPark Integration receives device data from Actility ThingPark Wireless, the LoRaWAN network server of Actility. ThingPark sends each uplink to ThingsBoard as an HTTP request with a DevEUI_uplink JSON body, and an uplink data converter transforms it into device data, including telemetry and attributes. For downlink, ThingsBoard sends commands to the device through the ThingPark downlink API.
Use ThingPark Integration when:
- Your LoRaWAN devices are registered in ThingPark Wireless, and ThingPark forwards their uplinks to an HTTP application server.
- You need to send commands from ThingsBoard to those devices, for example when a shared attribute changes.
For a ThingPark Enterprise deployment, use ThingPark Enterprise Integration instead. It has its own endpoint, always checks the request, and sends downlinks through the ThingPark Enterprise API.
Architecture
Section titled “Architecture”- Receive data. The device sends an uplink through a LoRaWAN gateway to ThingPark. ThingPark sends it as an HTTP
POSTwith aDevEUI_uplinkJSON body to the integration endpoint. With tunnel authentication, the request also carries theAS_ID,Time, andTokenquery parameters. - Check the request (optional). If Enable security is on, the integration checks the AS ID, the request time, and the token. A request that fails the check gets
403 Forbidden. - Decode the payload. The uplink converter takes the device payload out of the ThingPark message, decodes it into telemetry and attributes, and adds network fields such as
rssiandfCnt. If Allow create devices or assets is on, ThingsBoard creates the device on its first uplink. - Send a command (optional). The Rule Engine passes a message to the integration. The downlink converter encodes it as a hex payload, and ThingsBoard sends it right away to the ThingPark downlink API with the
DevEUIandFPort.
Prerequisites
Section titled “Prerequisites”- Access to ThingsBoard Cloud with integrations enabled for your tenant. The ThingsBoard endpoint must be reachable from the internet, because ThingPark calls it.
- Permission to create integrations and data converters, and to edit rule chains for downlink.
- An Actility ThingPark Wireless account with access to Device Manager, where you create application servers and routing profiles.
- A LoRaWAN device registered in ThingPark, and its DevEUI. Without a device, you can test the integration with curl.
Prepare ThingPark
Section titled “Prepare ThingPark”ThingPark forwards the uplinks of a device to the application servers in its AS routing profile. Here you check that the device is registered and look at the data ThingPark sends. The application server needs the integration endpoint, so you create it after creating the integration.
Register the Device
Section titled “Register the Device”Register the device in ThingPark Device Manager with its DevEUI, activation mode, and keys, as described in the ThingPark documentation. Menu names differ between ThingPark versions and plans.
ThingsBoard names the device after its DevEUI, for example Device 20635F00C5000660.
Uplink Message Format
Section titled “Uplink Message Format”ThingPark sends every uplink as a DevEUI_uplink JSON object. This guide uses the following uplink. Its payload_hex holds the payload of a sample device: a serial number, the battery level, the temperature, and the saturation.
{ "DevEUI_uplink": { "Time": "2026-10-22T10:15:30.123+00:00", "DevEUI": "20635F00C5000660", "FPort": 2, "FCntUp": 42, "ADRbit": 1, "MType": 2, "FCntDn": 5, "payload_hex": "00bc614e5f092950", "mic_hex": "3a1f9c4e", "Lrcid": "00000201", "LrrRSSI": -85.0, "LrrSNR": 7.25, "SpFact": 7, "SubBand": "G1", "Channel": "LC2", "DevLrrCnt": 1, "Lrrid": "FF0101B0", "Late": 0, "LrrLAT": 48.856613, "LrrLON": 2.352222, "CustomerID": "100000507", "DevAddr": "0405F519", "Frequency": 868.3, "DynamicClass": "A" }}DevEUI— the device EUI. ThingsBoard uses it in the device name.Time— when ThingPark received the uplink. The converter uses it as the telemetry timestamp.payload_hex— the device payload as a hex string. If a ThingPark driver decodes the payload, the message also has apayloadobject with the decoded values.LrrRSSI,LrrSNR,SpFact,SubBand,Channel— the radio data of the best gateway.CustomerID— your ThingPark customer ID. ThingPark uses it in the token of a signed request.
Set Up ThingPark Integration
Section titled “Set Up ThingPark Integration”Create the uplink converter and the integration, then create a ThingPark application server that sends uplinks to the integration endpoint.
Create the Uplink Data Converter
Section titled “Create the Uplink Data Converter”ThingPark Integration uses the Typed uplink converter. ThingsBoard selects it for this integration type, and you can’t change it later. The converter takes the device payload out of the DevEUI_uplink message before the decoder runs, and passes the network fields as metadata. For the full reference, see Typed uplink converter.
You can write the decoder yourself, or take a ready-made one from the Converters Library.
-
Go to Integrations ⇾ Data converters and click + Add data converter ⇾ Create new converter.
-
Converter type — keep Uplink.
-
Integration type — select ThingPark.
-
Keep Create new selected.
-
Name — enter a name, for example
ThingPark Uplink Converter. -
Main decoding configuration:
- Entity type — keep Device.
- Device name — keep
Device $eui. The converter replaces$euiwith theDevEUIof the uplink. You can use any key from Decoder Inputs as a$keyplaceholder. - The editor opens in TBEL with the ThingPark decoder below. Keep it for this guide. It decodes the sample payload from Uplink Message Format. For JavaScript, use the TBEL / JS toggle: it opens the same decoder in JavaScript.
/*** Decodes the incoming payload and returns a structured object containing telemetry data and attributes.** @param {byte[]} input - The raw payload received as an array of bytes.* @returns {Object} output - The structured output with decoded telemetry and attributes.*/function decodePayload(input) {// Initialize the output object with empty attributes and telemetry for clarity.var result = { attributes: {}, telemetry: {}};// Extract the timestamp from metadata (represented in milliseconds).var timestamp = metadata.ts; // ts is the timestamp parsed from the incoming message's time, or returns the current time if it cannot be parsed.if (metadata.payloadFormat == 'JSON') {// payloadFormat is 'JSON' when ThingPark sends a pre-decoded JSON payload// (DevEUI_uplink contains a "payload" object).// All fields from the decoded payload object are put directly into telemetry.var decoded = decodeToJson(input);result.telemetry = {ts: timestamp,values: decoded};return result;}// payloadFormat is 'BINARY' when raw hex payload is received (payload_hex field).// Decode serial number (SN) from the first 4 bytes of the payload.// Press '?' icon in the top right corner to learn more about built in helper functions and capabilities.result.attributes.sn = parseBytesToInt(input, 0, 4);// Combine the timestamp with decoded values and add it to the telemetry.result.telemetry = {ts: timestamp,values: {// Decode battery level from the 5th byte of the payload.battery: parseBytesToInt(input, 4, 1),// Decode temperature from the 6th and 7th bytes of the payload (divided by 100).temperature: parseBytesToInt(input, 5, 2) / 100.0,// Decode saturation from the 8th byte of the payload.saturation: parseBytesToInt(input, 7, 1)}};// Return the fully constructed output object.return result;}var result = decodePayload(payload);// Uncomment this code block to overwrite values set in the main configuration window. Useful if you extract device/asset/customer/group names from the payload;// result.type = 'DEVICE'; // Entity type allows you to choose type of created entity. Can be 'DEVICE' or 'ASSET'.// result.name = 'Temperature Sensor'; // Device or asset name (the value must be unique)// result.profile = 'IndustrialSensorProfile'; // Device or asset profile name.// result.customer = 'MyCustomer'; // If customer is not null - created entity will be assigned to customer with such name.// result.group = 'SensorsGroup'; // If group is not null - created entity will be added to the entity group with such name.// Return the final result object.return result;/*** Decodes the incoming payload and returns a structured object containing telemetry data and attributes.** @param {number[]} input - The raw payload received as an array of bytes.* @returns {Object} output - The structured output with decoded telemetry and attributes.*/function decodePayload(input) {// Initialize the output object with empty attributes and telemetry for clarity.var result = { attributes: {}, telemetry: {}};// Extract the timestamp from metadata (represented in milliseconds).var timestamp = metadata.ts; // ts is the timestamp parsed from the incoming message's time, or returns the current time if it cannot be parsed.if (metadata.payloadFormat == 'JSON') {// payloadFormat is 'JSON' when ThingPark sends a pre-decoded JSON payload// (DevEUI_uplink contains a "payload" object instead of raw "payload_hex").// All fields from the decoded payload object are put directly into telemetry.var decoded = decodeToJson(input);result.telemetry = {ts: timestamp,values: decoded};return result;}// payloadFormat is 'BINARY' when raw hex payload is received (payload_hex field).// Decode serial number (SN) from the first 4 bytes of the payload.// Press '?' icon in the top right corner to learn more about built in helper functions and capabilities.result.attributes.sn = parseBytesToInt(input, 0, 4);// Initialize an object to store decoded key/value telemetry data.var values = {};// Decode battery level from the 5th byte of the payload.values.battery = parseBytesToInt(input, 4, 1);// Decode temperature from the 6th and 7th bytes of the payload (divided by 100).values.temperature = parseBytesToInt(input, 5, 2) / 100.0;// Decode saturation from the 8th byte of the payload.values.saturation = parseBytesToInt(input, 7, 1);// Combine the timestamp with values and add it to the telemetry.result.telemetry = {ts: timestamp,values: values};// Return the fully constructed output object.return result;}var result = decodePayload(payload);// Uncomment this code block to overwrite values set in the main configuration window. Useful if you extract device/asset/customer/group names from the payload;// result.type = 'DEVICE'; // Entity type allows you to choose type of created entity. Can be 'DEVICE' or 'ASSET'.// result.name = 'Temperature Sensor'; // Device or asset name (the value must be unique)// result.profile = 'IndustrialSensorProfile'; // Device or asset profile name.// result.customer = 'MyCustomer'; // If customer is not null - created entity will be assigned to customer with such name.// result.group = 'SensorsGroup'; // If group is not null - created entity will be added to the entity group with such name.// Return the final result object.return result;/*** Converts a byte array to a string and parses it as JSON.** @param {number[]} payload - The array of bytes.* @returns {Object} - The parsed JSON object.*/function decodeToJson(payload) {return JSON.parse(String.fromCharCode.apply(String, payload));}/*** Parse a slice of bytes from an array into an integer (big-endian).** @param {number[]} input - The array of bytes.* @param {number} offset - The starting index.* @param {number} length - The number of bytes to convert.* @returns {number} - The resulting integer.*/function parseBytesToInt(input, offset, length) {var result = 0;for (var i = offset; i < offset + length; i++) {result = (result << 8) | (input[i] & 0xFF);}return result;}To adapt:
- Payload layout — change the offsets and lengths in
decodePayloadto match the payload format of your device. - Decoded payload — if a ThingPark driver decodes the payload,
metadata.payloadFormatisJSON, and the decoder stores the decoded values as telemetry as they are. - Device identity — set
result.name,result.profile,result.customer, orresult.groupto override the fields of Main decoding configuration and Advanced decoding parameters.
-
Advanced decoding parameters — review the pre-filled values:
- Device profile name, Device label, Customer name, Device group name — empty by default. Without a profile name, ThingsBoard uses the
defaultprofile. Each field accepts$keyplaceholders. - Telemetry —
fCnt,data,rssi,snr,channel, anddecoded. The converter adds these metadata keys to the telemetry that the decoder returns. It skips a key that is missing from the uplink or that the decoder already returns. - Attributes —
eui,fPort,adr,spreadingFactor,bandwidth,devAddr,frequency, andclass. The converter adds them to the attributes in the same way. Downlink needseui, so keep it. - Update only keys list — the same keys as Attributes. These keys are stored only when their value changes.
- Device profile name, Device label, Customer name, Device group name — empty by default. Without a profile name, ThingsBoard uses the
-
Click Test payload decoder and check the result (see Test the Decoder).
-
Click Add.
Decoder Inputs
| Variable | Type | Content |
|---|---|---|
payload |
byte array | The device payload: the bytes of payload_hex, or the decoded payload object as JSON bytes if ThingPark sends one. Empty if the uplink has neither. |
metadata |
object | The fields that the converter takes from the DevEUI_uplink message, and the integration metadata. |
For the uplink in Uplink Message Format, metadata holds these keys:
| Key | Source | Value in this guide |
|---|---|---|
eui |
DevEUI |
20635F00C5000660 |
fPort, fCnt, fCntDn |
FPort, FCntUp, FCntDn |
2, 42, 5 |
data |
payload_hex |
00bc614e5f092950 |
rssi, snr |
LrrRSSI, LrrSNR |
-85.0, 7.25 |
spreadingFactor, bandwidth, channel |
SpFact, SubBand, Channel |
7, G1, LC2 |
adr, mType, devAddr, frequency |
ADRbit, MType, DevAddr, Frequency |
1, 2, 0405F519, 868.3 |
time, timeTs, ts |
Time |
2026-10-22T10:15:30.123+00:00, 1792664130123, 1792664130123 |
payloadFormat |
— | BINARY for payload_hex, JSON for a decoded payload |
integrationName |
integration | The name of the integration. |
AS_ID, LrnDevEui, LrnFPort |
request query parameters | The values ThingPark sends, or false if the request has no such parameter. |
The converter also maps micHex, lrcid, lrrId, late, latitude, longitude, lrr, devLrrCnt, customerId, customerData, dynamicClass, decoded, and other DevEUI_uplink fields when the uplink has them. ts is the time of the uplink in milliseconds, or the current time if Time is missing or can’t be parsed. A key from the integration’s Metadata field overrides a ThingPark key with the same name.
Test the Decoder
Click Test payload decoder below the editor. To test with the uplink from Uplink Message Format, click Updated RAW payload, paste the message, and click Apply. The dialog takes the device payload out of the message and fills Payload and Metadata with it. Click Test. The Output panel shows the decoder result:
{ "attributes": { "sn": 12345678 }, "telemetry": { "ts": 1792664130123, "values": { "battery": 95, "temperature": 23.45, "saturation": 80 } }}The keys from Telemetry and Attributes in Advanced decoding parameters are added after the decoder runs. You see them on the device after the first uplink. If the output is empty or shows an error, fix the decoder and test again.
Use the Converters Library
The Converters Library holds ready-made decoders for many LoRaWAN devices, from the open-source data-converters repository.
- In + Add data converter ⇾ Create new converter, keep Uplink, select ThingPark, and switch Create new to Library. The Uplink data converter step of the integration wizard offers the same Library option.
- Select the Vendor and the Model of your device.
- The Name is filled in, in the form
ThingPark Uplink Converter for <Vendor> <Model>, and the decoder is loaded. - Review the decoder and the Advanced decoding parameters, and click Add.
A library decoder can differ from the decoder in this guide. Some entries are written for the full ThingPark message: they decode the DevEUI_uplink object themselves, and the dialog then offers Test decoder function and only Update only keys list under Advanced decoding parameters. Test a library decoder with an uplink of your device before you use it.
Create the Integration
Section titled “Create the Integration”- Go to Integrations ⇾ Integrations and click + Add integration.
- Basic settings:
- Integration type — select ThingPark.
- Name — keep the default
ThingPark 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
ThingPark Uplink Converter. - Alternatively, click Create new or Library to create the converter here.
- Click Next.
- Click Select existing and choose
- Downlink data converter:
- Click Skip. Add a downlink converter later if you need to send commands.
- Connection:
- Copy the HTTP endpoint URL. You need it for the ThingPark application server.
- Leave the other parameters at their defaults. See Connection Settings for details.
- Click Add.
Connection Settings
Section titled “Connection Settings”| Parameter | Default | Description |
|---|---|---|
| Base URL | Address of the ThingsBoard server you are signed in to, for example https://thingsboard.cloud |
Used to build the endpoint URL. Must be a public address. Required. |
| HTTP endpoint URL | — | Read-only. Format: {Base URL}/api/v1/integrations/thingpark/{integrationKey}, where integrationKey is a UUID assigned at creation. Accepts JSON bodies only. |
| Enable security | Off | Checks the AS_ID, Time, and Token query parameters of every uplink, and signs every downlink. See Secure the Endpoint. |
| AS ID | — | In Enable security. The application server ID set in ThingPark. Compared without regard to case. Required when Enable security is on. |
| AS Key | — | In Enable security. The tunnel authentication key of the application server in ThingPark. Required when Enable security is on. |
| Maximum time difference (seconds) | 60 |
In Enable security. Maximum difference between the Time of a request and the clock of the ThingsBoard server. |
| Enable security for automatic token updates | Off | In Enable security. Used by ThingPark Enterprise Integration only. Keep it off: ThingPark Integration ignores its fields, and the toggle hides the AS ID field that the integration reads. |
| Execute remotely | Off | Runs the integration as a separate process outside the ThingsBoard cluster. ThingsBoard generates an Integration key and Integration secret for it. ThingPark needs a public endpoint, so the standard setup keeps this off. See Remote Integration. |
| Replace response status from ‘No-Content’ to ‘OK’ | Off | In Advanced settings. Has no effect for ThingPark Integration: it always answers 200 OK to an accepted uplink. |
| Downlink URL | https://api.thingpark.com/thingpark/lrc/rest/downlink |
In Advanced settings. The ThingPark downlink API. Used only when a downlink converter is assigned. Change it if your ThingPark installation uses another host. |
| Description | — | In Advanced settings. Free-text description. |
| Metadata | — | In Advanced settings. Key–value pairs added to the metadata of every message from this integration. |
The integration answers 200 OK when it accepted the uplink, 400 Bad Request on a converter script error, 403 Forbidden when the security check fails, and 500 Internal Server Error on other errors, for example a body without DevEUI_uplink.
Connect ThingPark to ThingsBoard
Section titled “Connect ThingPark to ThingsBoard”In ThingPark Device Manager, create an application server that sends uplinks to the integration endpoint, and route the device to it.
- Create an HTTP application server. Set the content type to JSON, and add the HTTP endpoint URL of the integration as its destination.
- To sign the requests, turn on tunnel interface authentication for the application server, and note its AS ID and AS key. You enter them in ThingsBoard in Secure the Endpoint.
- Create an AS routing profile with the application server as its destination.
- Assign the routing profile to the device.
Menu and field names differ between ThingPark versions. For the exact steps, see the ThingPark documentation.
Secure the Endpoint
Section titled “Secure the Endpoint”Anyone who knows the endpoint URL can send data to it. With Enable security, the integration accepts only uplinks signed with the AS key of your application server. It rejects every other request with 403 Forbidden, before the converter runs.
- In ThingsBoard, open the integration and click Toggle edit mode (pencil icon).
- Turn on Enable security. Keep Enable security for automatic token updates off.
- Enter the AS ID and the AS Key of the application server.
- Keep Maximum time difference (seconds) at
60, or increase it if the clocks of ThingPark and ThingsBoard differ. - Click Apply changes.
For each uplink, the integration checks that:
- The
AS_IDquery parameter matches the AS ID. - The
Timequery parameter, for example2026-10-22T10:15:30.123Z, differs from the server time by no more than Maximum time difference (seconds). - The
Tokenquery parameter is the SHA-256 hash, in lowercase hex, of this string: theCustomerID,DevEUI,FPort,FCntUp, andpayload_hexvalues of the body, thenLrnDevEui={…}&LrnFPort={…}&LrnInfos={…}&AS_ID={…}&Time={…}with the query parameter values, then the AS Key.
A signed request must have all of these fields. To send a signed test request, see Send a Signed Test Uplink.
Test Uplink
Section titled “Test Uplink”Send an uplink to the endpoint, then confirm that ThingsBoard decoded it and created the device.
Send a Test Uplink
Section titled “Send a Test Uplink”Wait for the device to send an uplink through ThingPark, or send the uplink from Uplink Message Format with curl. The curl request bypasses ThingPark, so you can check the integration before you connect a device.
Replace $HTTP_ENDPOINT_URL with the HTTP endpoint URL of the integration. Enable security must be off.
curl -i -X POST "$HTTP_ENDPOINT_URL" \ -H "Content-Type: application/json" \ -d '{"DevEUI_uplink": {"Time": "2026-10-22T10:15:30.123+00:00", "DevEUI": "20635F00C5000660", "FPort": 2, "FCntUp": 42, "ADRbit": 1, "MType": 2, "FCntDn": 5, "payload_hex": "00bc614e5f092950", "mic_hex": "3a1f9c4e", "Lrcid": "00000201", "LrrRSSI": -85.0, "LrrSNR": 7.25, "SpFact": 7, "SubBand": "G1", "Channel": "LC2", "DevLrrCnt": 1, "Lrrid": "FF0101B0", "Late": 0, "LrrLAT": 48.856613, "LrrLON": 2.352222, "CustomerID": "100000507", "DevAddr": "0405F519", "Frequency": 868.3, "DynamicClass": "A"}}'The response is HTTP/1.1 200. The telemetry is stored with the timestamp of Time, so it appears under 22 October 2026.
Send a Signed Test Uplink
With Enable security on, sign the request as ThingPark does. Set AS_ID and AS_KEY to the values in the integration. The script uses the current UTC time, so the request passes the time check.
AS_ID="TWA_100000507.2378.AS"AS_KEY="0123456789abcdef0123456789abcdef"TIME=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)QUERY="LrnDevEui=20635F00C5000660&LrnFPort=2&LrnInfos=TWA_100000507.2378.AS&AS_ID=${AS_ID}&Time=${TIME}"# CustomerID, DevEUI, FPort, FCntUp, and payload_hex of the body belowBODY_FIELDS="100000507""20635F00C5000660""2""42""00bc614e5f092950"TOKEN=$(printf '%s' "${BODY_FIELDS}${QUERY}${AS_KEY}" | sha256sum | cut -d' ' -f1)
curl -i -X POST "${HTTP_ENDPOINT_URL}?${QUERY}&Token=${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"DevEUI_uplink": {"Time": "2026-10-22T10:15:30.123+00:00", "DevEUI": "20635F00C5000660", "FPort": 2, "FCntUp": 42, "payload_hex": "00bc614e5f092950", "LrrRSSI": -85.0, "LrrSNR": 7.25, "SpFact": 7, "SubBand": "G1", "Channel": "LC2", "CustomerID": "100000507", "DevAddr": "0405F519", "Frequency": 868.3}}'On macOS, replace sha256sum with shasum -a 256. A wrong AS key gives 403. The integration event then has the status FORBIDDEN.
Verify the Result
Section titled “Verify the Result”- Integration events — go to Integrations ⇾ Integrations, open the integration, and click the Events tab. The message appears as an event of type Uplink with status OK. Click
⋅⋅⋅in the Message column to see the body. - Converter events — open
ThingPark Uplink Converterin Integrations ⇾ Data converters and click the Events tab. In shows the fullDevEUI_uplinkmessage, as ThingPark sent it. Out shows the decoder result. Metadata shows the integration metadata as it was before the converter read the message:integrationName,AS_ID,LrnDevEui, andLrnFPort. - Device — go to Devices & assets ⇾ Devices. The integration has created the device
Device 20635F00C5000660with thedefaultprofile. Open it and check:- Latest telemetry —
battery95,temperature23.45, andsaturation80from the decoder, andfCnt,data,rssi,snr, andchannelfrom Advanced decoding parameters. - Attributes ⇾ Client attributes —
sn12345678from the decoder, andeui,fPort,adr,spreadingFactor,bandwidth,devAddr, andfrequencyfrom Advanced decoding parameters.
- Latest telemetry —
Configure Downlink
Section titled “Configure Downlink”ThingsBoard sends each downlink right away as a ThingPark API call. Nothing is queued in ThingsBoard: if the call fails, ThingsBoard records an error and drops the command. ThingPark then delivers the downlink to the device, for a class A device after its next uplink.
For each downlink, the integration:
- Reads
DevEUIandFPortfrom themetadataof the encoder result, and the hex payload fromdata. - Sends
POST {Downlink URL}?DevEUI={DevEUI}&FPort={FPort}&Payload={data}with an emptytext/plainbody. It addsFCntDn,Confirmed, andFlushDownlinkQueuewhen the encoder metadata has them. - If Enable security is on, adds
AS_ID,Time, andTokento the query. The token is the SHA-256 hash, in lowercase hex, of the query string followed by the AS Key.
Without Enable security, the request is not signed. Turn it on if your ThingPark application server uses tunnel interface authentication.
The downlink converter turns a Rule Engine message into the encoder result. For the full encoder reference, see Downlink data converter.
Create and Assign the Downlink Converter
Section titled “Create and Assign the Downlink Converter”- 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 ThingPark integration type are preselected.
- Enter a name, for example
ThingPark Downlink Converter. - Main encoding configuration opens in TBEL with a generic encoder. It builds a JSON object from
temperatureUploadFrequencyandhumidityUploadFrequencyand sets an MQTTtopic, not the hex payload,DevEUI, andFPortthat ThingPark needs. Replace it with the encoder below. For JavaScript, use the TBEL / JS toggle and the JavaScript tab. - To record downlink events, click the debug button next to the name, select All messages, and click Apply. Debug is off by default.
- Click Add.
- Click Apply changes.
Encoder used in this guide. It sends the uploadInterval shared attribute, in seconds, as a 2-byte big-endian hex payload, for example 003C for 60. A message without uploadInterval produces no downlink. Change the payload format to the one your device expects.
/** Encoder **/
// Device EUI. The rule chain adds the eui client attribute to the metadata as cs_eui.var devEui = metadata['cs_eui'];if (devEui == null) { raiseError("DevEUI not found: the device has no eui client attribute.");}
// Nothing to send.var interval = msg['uploadInterval'];if (interval == null) { return [];}
// Upload interval in seconds (0-65535) as 2 bytes, big-endian, in hex. 60 -> "003C".var payloadHex = padStart(intToHex(interval, true, false), 4, '0');
return { contentType: "TEXT", data: payloadHex, metadata: { DevEUI: devEui, // LoRaWAN port your device listens on for commands. FPort: 2 }};/** Encoder **/
// Device EUI. The rule chain adds the eui client attribute to the metadata as cs_eui.var devEui = metadata['cs_eui'];if (devEui == null) { throw new Error("DevEUI not found: the device has no eui client attribute.");}
// Nothing to send.var interval = msg['uploadInterval'];if (interval == null) { return [];}
// Upload interval in seconds (0-65535) as 2 bytes, big-endian, in hex. 60 -> "003C".var payloadHex = ('000' + Number(interval).toString(16).toUpperCase()).slice(-4);
return { contentType: "TEXT", data: payloadHex, metadata: { DevEUI: devEui, // LoRaWAN port your device listens on for commands. FPort: 2 }};To check the encoder, click Test encoder function. Replace the Message with {"uploadInterval": 60}, add the key cs_eui with the value 20635F00C5000660 to Metadata, and click Test. The Output panel shows:
{ "contentType": "TEXT", "data": "003C", "metadata": { "DevEUI": "20635F00C5000660", "FPort": 2 }}The integration reads these fields from the encoder result:
| Field | Required | Description |
|---|---|---|
data |
Yes | The payload, sent as the Payload query parameter as is. Use a hex string. |
contentType |
Yes | TEXT for a hex string. JSON works the same way. BINARY expects Base64 and sends the decoded bytes as text, so don’t use it. |
metadata.DevEUI |
Yes | The device EUI. Without it, the downlink fails with DevEUI is missing in the downlink metadata!. |
metadata.FPort |
Yes | The LoRaWAN port. The name is case-sensitive: without FPort, the downlink fails with FPort is missing in the downlink metadata!. |
metadata.FCntDn |
No | Downlink frame counter, sent as FCntDn. |
metadata.Confirmed |
No | Sent as Confirmed, for a confirmed downlink. |
metadata.FlushDownlinkQueue |
No | Sent as FlushDownlinkQueue, to clear the ThingPark downlink queue of the device first. |
For the values ThingPark accepts in these parameters, see the ThingPark documentation. To send several downlinks from one message, return an array of results.
Configure the Root Rule Chain
Section titled “Configure the Root Rule Chain”The encoder needs the device EUI. Add the eui client attribute to the metadata with an originator attributes node, then pass the message to the integration.
- Go to Data processing ⇾ Rule chains and open the Root Rule Chain.
- From the Enrichment section, drag an originator attributes node onto the canvas:
- Name — for example
Fetch eui. - Client attributes — add
eui. - Add originator attributes to — keep Metadata. The node adds the attribute as
cs_eui. - Click Add.
- Name — for example
- From the Action section, drag an integration downlink node onto the canvas:
- Name — for example
Downlink to ThingPark. - Integration — select
ThingPark integration. - Click Add.
- Name — for example
- Connect the message type switch node to
Fetch euiwith the Attributes Updated relation. - Connect
Fetch euitoDownlink to ThingParkwith the Success relation. - Click Apply changes.
Shared attribute updates of every device now reach the encoder. A device without the eui attribute produces an error event in the downlink converter. If your tenant has other devices, route only ThingPark devices to the node, for example by device profile.
Test Downlink
Section titled “Test Downlink”- Go to Devices & assets ⇾ Devices and open the device created in Test Uplink.
- On the Attributes tab, select Shared attributes and click +.
- Enter Key
uploadInterval, select the Integer type, enter Value60, and click Add.
Verify the Downlink
Section titled “Verify the Downlink”- Converter events — open
ThingPark Downlink Converterin Integrations ⇾ Data converters and click the Events tab. In shows the message{"uploadInterval": 60}withcs_euiin its metadata. Out shows the payload003C, theDevEUI, and theFPort. - Integration events — open the integration’s Events tab. Downlink: ATTRIBUTES_UPDATED shows the message from the Rule Engine. A Downlink event with status OK shows that ThingPark accepted the call. A failed call appears with an error and the ThingPark response.
- ThingPark — open the ThingPark Wireless Logger and check for a downlink entry for the device.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Fix |
|---|---|---|
| No events on the integration Events tab | The device has no routing profile with the application server, the destination URL is wrong, or the integration is disabled. Or debug mode is off: it records events for 15 minutes after you turn it on. | Check the AS routing profile of the device and the destination of the application server. Copy the HTTP endpoint URL again. Turn on Enable integration. Turn debug mode on again. |
| Uplink events with status FORBIDDEN, and no converter events | Enable security is on, and the AS ID, the time, or the token does not match. | Check that the AS ID and AS Key match the application server. Check the clocks, or increase Maximum time difference (seconds). |
| Same, after you turned on Enable security for automatic token updates | The toggle hides the AS ID field that ThingPark Integration reads. | Turn the toggle off, enter the AS ID again, and click Apply changes. |
Uplink events with status ERROR and Unparseable date: "false" |
Enable security is on, but the request has no Time parameter: ThingPark does not sign it. |
Turn on tunnel interface authentication for the application server in ThingPark, or turn off Enable security. |
Uplink events with status ERROR and a NullPointerException |
The body has no DevEUI_uplink object. With Enable security on, the body also needs CustomerID, DevEUI, FPort, FCntUp, and payload_hex. |
Send only uplink messages to the endpoint. Check In in the integration event. |
| Converter events with an error | The decoder failed. | Check the Error column in the converter events and fix the decoder. |
| Telemetry values are wrong or missing | The decoder does not match the payload format of the device. | Compare payload_hex in In with the device documentation, and fix the offsets in decodePayload. |
A decoded telemetry key with a JSON object |
A ThingPark driver decodes the payload, and decoded is in the Telemetry list. |
Remove decoded from Telemetry in Advanced decoding parameters. |
| Device not created | Allow create devices or assets is off, or the device name is empty. | Turn the option on. Check Device name and Out in the converter events. |
DevEUI is missing in the downlink metadata! |
The encoder did not set metadata.DevEUI. |
Check that the device has the eui client attribute and that Fetch eui adds it to the metadata. |
FPort is missing in the downlink metadata! |
The encoder does not set metadata.FPort, or uses another spelling, such as fPort. |
Use the encoder from this guide. |
| No downlink and no error | No downlink converter is assigned, the rule chain does not route attribute updates, or the encoder returned [] because the message had no uploadInterval. |
Assign the converter and check the Attributes Updated relation. Check Out in the downlink converter events. |
| Downlink event with an error and a ThingPark response | The Downlink URL is wrong, the request is not signed or is signed with a wrong AS ID or AS key, or the payload is not hex. | Check the Downlink URL in Advanced settings, Enable security, and Out in the downlink converter events. |
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.
- ThingPark Enterprise Integration — connect a ThingPark Enterprise deployment.
- Uplink data converter — Typed converter, Converters Library, and decoder reference.
- Downlink data converter — encoder reference.
- integration downlink node — route Rule Engine messages to an integration.
- originator attributes node — add attributes of the message originator to the metadata.
- message type switch node — route messages by type, for example attribute updates.
- Remote Integration — run the integration outside the ThingsBoard cluster.
- TBEL — built-in functions and syntax for converter scripts.
- Abeeway Trackers with Actility ThingPark — end-to-end example with Abeeway trackers, converters, and a dashboard.
- ThingPark documentation — application servers, routing profiles, tunnel interface authentication, and the downlink API.
Was this helpful?