Write a Decoder
Overview
Write a decoder in JavaScript that turns the bytes of a device's uplink into JSON values, such as a temperature in °C. You add it to a Custom v2 data converter in TEKTELIC KONA Core Network Server. At the end, every integration that uses the converter delivers readable data to your system.
The predefined TEKTELIC converter types work only with legacy V1 integrations. For TEKTELIC devices, you can copy a published V2 decoder: see TEKTELIC Device Converters Library. To write your own Custom v2 decoder, follow this guide. What converters are and where they run is explained in Payload Converters Overview.
Before you start
- Role: Customer administrator or Sub-Customer administrator. The Customer user role opens Data converters read-only. The Sub-Customer user role doesn't see Data converters. See Users, Roles & Permissions.
- Payload description: the device's payload format from its manufacturer. It says which bytes hold which value, the byte order, the scale and the FPort of each message type.
- Sample payloads: a few real uplinks of the device, as bytes, with the values you expect from them. You find the payload bytes on the device's Real-time packets tab: see Device Activity & Status.
- Optional, for local tests: Node.js or a browser console, to run the decoder before you add it to KONA Core.
Steps
Understand the decoder function
KONA Core wraps your code in this function. You write only the function body:
function decodeUplink(input) {
// your code
}
The input object has these fields, as the default template in the editor lists them:
| Field | Type | What it holds |
|---|---|---|
bytes | int[] | The uplink payload, one integer per byte. |
fPort | int | The FPort of the uplink. |
recvTime | Date | The time KONA Core received the uplink. The template says "needs type check": test input.recvTime instanceof Date before you use it. |
tektelicMetadata | Object | Device, application, frame and radio metadata. See Message Formats. |
Return an object with these fields:
| Field | Type | What it holds |
|---|---|---|
data | Object | Your decoded values. This is the data your integration delivers. |
errors | string[] | Errors found while decoding. Use an empty array when there are none. |
warnings | string[] | Warnings, for example an unknown message type. Use an empty array when there are none. |
tektelicMetadata | Object | Return input.tektelicMetadata unchanged, as the template does. |
KONA Core merges data and tektelicMetadata into the delivered body; data wins if keys overlap. The errors and warnings arrays aren't delivered. confirm how KONA Core handles a non-empty errors array.
The default template of a new Custom v2 converter shows the same structure:
// input object structure:
// - bytes - int[]
// - fPort - int
// - recvTime - Date (needs type check)
// - tektelicMetadata - Object
if (input.recvTime instanceof Date) {
// date operations
}
// output object structure:
// - data - Object
// - errors - string[]
// - warnings - string[]
// - tektelicMetadata - Object
return {
"data": {},
"errors": [],
"warnings": [],
"tektelicMetadata": input.tektelicMetadata
};
The decoder execution timeout is 100 ms. If a decoder exceeds it 5 times within 600 seconds, KONA Core bans it for 30 minutes. the timeout note says a ban follows 5 timeouts within 600 seconds, the ban message says the code is banned "due to errors during execution"; confirm whether other errors also count toward a ban. Keep the code short: no loops over large data and no waiting.
We recommend plain ES5 syntax, as in the template: var, function and no arrow functions.
Write the decoder
The example below decodes a fictional "Example sensor". It isn't a real device: use it as a pattern for your own payload. The sensor sends 4 bytes on FPort 10:
| Bytes | Value | Format |
|---|---|---|
| 0–1 | Temperature | Signed 16-bit integer, big-endian, in 0.1 °C |
| 2 | Relative humidity | Unsigned integer, in % |
| 3 | Door state | Bit 0: 1 means open |
For example, the bytes 00 EB 2D 01 mean 23.5 °C, 45 % and door open.
// Fictional "Example sensor": 4 bytes on FPort 10.
var data = {};
var errors = [];
var warnings = [];
if (input.fPort !== 10) {
warnings.push("Unknown FPort " + input.fPort + ": payload not decoded");
} else if (input.bytes.length !== 4) {
errors.push("Expected 4 bytes, received " + input.bytes.length);
} else {
// Bytes 0-1: signed 16-bit integer, big-endian, 0.1 degree C
var raw = (input.bytes[0] << 8) | input.bytes[1];
if (raw > 0x7FFF) {
raw = raw - 0x10000;
}
data.temperature = raw / 10;
// Byte 2: relative humidity in %
data.humidity = input.bytes[2];
// Byte 3, bit 0: door state
data.doorOpen = (input.bytes[3] & 0x01) === 1;
}
return {
"data": data,
"errors": errors,
"warnings": warnings,
"tektelicMetadata": input.tektelicMetadata
};
Check the length and the port before you read bytes. A decoder that reads past the end of bytes gets undefined and returns wrong values instead of an error.
Test the decoder locally
The converter editor has no test run: KONA Core runs the decoder only on real uplinks. Test your code first on your computer.
-
Create a file
test-decoder.jswith this content. Paste your decoder body inside the function:function decodeUplink(input) {// paste the decoder body here}console.log(JSON.stringify(decodeUplink({bytes: [0x00, 0xEB, 0x2D, 0x01],fPort: 10,recvTime: new Date(),tektelicMetadata: {}}))); -
Run
node test-decoder.jsin a terminal. For the example sensor, the output is:{"data":{"temperature":23.5,"humidity":45,"doorOpen":true},"errors":[],"warnings":[],"tektelicMetadata":{}} -
Repeat with each sample payload and with edge cases: a negative temperature (first 2 bytes
FF 9Cgive -10), a short payload, another FPort.
Add the decoder to KONA Core
-
In the side menu, select Data converters. The page lists your converters with Created Time, Name, Type, Decoder banned and Encoder banned.

-
Select the + icon at the top right. The Add Data Converter dialog opens.
-
Enter a Name, for example the device model. The name is required.
-
In Type, select Custom v2. The Decoder and Encoder editors open with the default templates.
-
In the Decoder editor, replace the template body with your decoder. The lines
function decodeUplink(input) {and}stay outside the editor.
-
If the device takes no downlinks through the integration, leave the Encoder template as it is. To write one, see Write an Encoder.
-
Select Add. The converter appears in the list with the type Custom v2. confirm whether KONA Core checks the code when you save a converter, and which message it shows for invalid code.
The Custom type uses the legacy V1 signature Decoder(bytes, port). Use Custom v2 for new converters. For V1, see Migrate from V1 to V2.
To create a converter from your own system, use Save converter.
Edit an existing decoder
-
In Data converters, select the converter's name. The Data converter details panel opens. It shows the execution timeout and ban rule above the editors.

-
Select the pencil icon (Toggle edit mode).
-
Change the code in the Decoder editor.
-
Select the check mark icon (Apply changes). KONA Core uses the new code for the next uplinks. confirm that saving a fixed decoder doesn't lift an active ban before the 30 minutes end.
Use the decoder in an integration
Select the converter in the Data converter field when you add or edit an integration. You find integrations on the application: Manage integrations > Add Integration. HTTP_V2, MQTT_V2 and MQTT_BROKER list only Custom v2 converters. See MQTT Broker Integration, HTTP Integration or MQTT Integration.
The data object of your result is what the integration sends to your system. For the full message, see Message Formats.
Check the result
-
Wait for the next uplink of a device in the application.
-
In your system, check the message from the integration. Its data holds the values your decoder returned, for example
temperature,humidityanddoorOpen. -
In Data converters, check that Decoder banned shows No for your converter.
-
Select the statistics icon in your converter's row, or Show converter statistics on the details panel. The Converter statistics dialog shows Encoder and Decoder counters, by Day and Month, for the date you select.
-
In the Decoder columns, check that Invoked grows with each uplink and Invocation failed (total) stays at 0. Select Close.

The same counters are in the API: Get converter decoder stats by converter ID. To follow integration errors over time, see Integration Monitoring.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
Invocation failed (total) grows, and KONA Core raises INTEGRATION_UL_DECODING_FAILURE. | The decoder throws an exception, for example on a payload shorter than expected or on an FPort it doesn't handle. | Run the failing payload through your local test. Check the length and the port before you read bytes. |
| Decoder banned shows Yes. The editor shows . | The decoder exceeded the 100 ms timeout 5 times within 600 seconds. KONA Core raises DECODER_BANNED and skips its runs for 30 minutes. | Remove slow code, such as long loops. Fix the decoder and wait for the ban to end. Invocation skipped due the converter is banned shows the uplinks that weren't decoded. |
| Your system receives wrong values, but no error. | Wrong byte order, scale or sign, or a different payload version. | Compare the decoder with the manufacturer's payload description. Test it locally with the bytes from Real-time packets. |
To get notified when a decoder is banned, add an application alarm rule with the trigger Decoder is banned. See Configure Application Alarm Rules and Events & Alarms.
Still stuck? A Sub-Customer contacts their Customer, and a Customer contacts their Provider. Send the converter name, the DevEUI of a device, the time of a failed uplink in UTC, the payload bytes and your decoder code.