Skip to main content

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:

FieldTypeWhat it holds
bytesint[]The uplink payload, one integer per byte.
fPortintThe FPort of the uplink.
recvTimeDateThe time KONA Core received the uplink. The template says "needs type check": test input.recvTime instanceof Date before you use it.
tektelicMetadataObjectDevice, application, frame and radio metadata. See Message Formats.

Return an object with these fields:

FieldTypeWhat it holds
dataObjectYour decoded values. This is the data your integration delivers.
errorsstring[]Errors found while decoding. Use an empty array when there are none.
warningsstring[]Warnings, for example an unknown message type. Use an empty array when there are none.
tektelicMetadataObjectReturn 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:

BytesValueFormat
0–1TemperatureSigned 16-bit integer, big-endian, in 0.1 °C
2Relative humidityUnsigned integer, in %
3Door stateBit 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.

  1. Create a file test-decoder.js with 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: {}
    })));
  2. Run node test-decoder.js in a terminal. For the example sensor, the output is:

    {"data":{"temperature":23.5,"humidity":45,"doorOpen":true},"errors":[],"warnings":[],"tektelicMetadata":{}}
  3. Repeat with each sample payload and with edge cases: a negative temperature (first 2 bytes FF 9C give -10), a short payload, another FPort.

Add the decoder to KONA Core​

  1. In the side menu, select Data converters. The page lists your converters with Created Time, Name, Type, Decoder banned and Encoder banned.

    Data converters page with the converter list

  2. Select the + icon at the top right. The Add Data Converter dialog opens.

  3. Enter a Name, for example the device model. The name is required.

  4. In Type, select Custom v2. The Decoder and Encoder editors open with the default templates.

  5. In the Decoder editor, replace the template body with your decoder. The lines function decodeUplink(input) { and } stay outside the editor.

    Add Data Converter dialog with the Custom v2 type and the Decoder and Encoder editors

  6. If the device takes no downlinks through the integration, leave the Encoder template as it is. To write one, see Write an Encoder.

  7. 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​

  1. 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.

    Data converter details panel with the timeout note and the Decoder editor

  2. Select the pencil icon (Toggle edit mode).

  3. Change the code in the Decoder editor.

  4. 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​

  1. Wait for the next uplink of a device in the application.

  2. In your system, check the message from the integration. Its data holds the values your decoder returned, for example temperature, humidity and doorOpen.

  3. In Data converters, check that Decoder banned shows No for your converter.

  4. 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.

  5. In the Decoder columns, check that Invoked grows with each uplink and Invocation failed (total) stays at 0. Select Close.

    Converter statistics for a data converter

The same counters are in the API: Get converter decoder stats by converter ID. To follow integration errors over time, see Integration Monitoring.

Troubleshooting​

SymptomLikely causeWhat 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 Decoder is banned due to errors during execution. Please check your code.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.