All Collections
Technical Resources
Ubidots Decoders as a Service
Ubidots Decoders as a Service

Run public Javascript decoders using our public DaaS API (Decoders as a Service)

Sergio M avatar
Written by Sergio M
Updated over a week ago

The LoRaWAN ecosystem continues to grow, and so does the length of the decoders needed to transform binary or Base64 payloads into friendly JSON ones. Copy/pasting such decoders can get confusing for two reasons:

  • Some of them have hundreds of lines of code — and continue to grow as more sensors and features are added to the devices.

  • Most —if not all— LoRaWAN vendors offer their decoders in NodeJS, making them incompatible if you're developing your functions in Python.

Because of this, we created a public DaaS (Decoder as a Service) endpoint.

Requirements

  • An Ubidots active account

  • A NodeJS code hosted publicly

Table of Contents

1. Understanding manufacturer-provided decoders

Most IoT devices send their data in binary or hexadecimal formats. However, most IoT cloud applications expect incoming data to be in a JSON structure, with sensor readings in decimal format. This process is known as "decoding" the device data.

Given that most LoRaWAN device manufacturers provide decoding functions, we created a public decoding service so you can run such code through a simple API request, erasing the need to copy-paste it into a LoRaWAN console, run it in your own server, or even in an UbiFunction.

2. How to use Ubidots DaaS

In order to use Ubidots DaaS all you need to do is make a POST request to the following URL:

HTTP Method

URL

POST

https://functions.ubidots.com/pub/decode/custom

Using the following HTTP Headers:

Header

Value

Content-Type

application/json

X-Auth-Token

<your-ubidots-token>

With a JSON payload containing the following keys:

Key

Value

Example

url

The public URL containing the code you wish to execute. Expects a raw text.

https://raw.githubusercontent.com/Seeed-Solution/TTN-Payload-Decoder/master/SenseCAP_S2120_Weather_Station_Decoder.js

payload

JSON payload, whose keys are the arguments expected by the decoder

{
"fPort": 1,
"bytes":"SGVssIHdvckIQ="
}

function

The main function in the decoder

decodeUplink

Note: When using GitHub, please set the URL to raw text mode.

Example

Consider that the decoder you wish to use is hosted in the following URL:

https://raw.repository.com/myDecoder.js

Such decoder contains a function called decodeUplink , such as:

function decodeUplink(args)
{
var bytes = args.bytes;
var port = args.fPort;
//Some other code that parses data
return {"temperature" : xxx, "humidity" : yyy};
}

Since it expects both the fPort and bytes keys, you'd need to send exactly the same JSON in the payload.

The body for a request to this decoder would look like:

{
"url": "https://raw.repository.com/myDecoder.js",
"payload": {
"fPort": 1,
"bytes": "SGVsbG8sIHdvcmxkIQ="
},
"function": "decodeUplink"
}

After making the request, it should return the same object as in the decoder, in this case:

{"temperature" : xxx, "humidity" : yyy}

3. DaaS implementation in NodeJS

The following is a simple implementation in NodeJS on how to make such request. You can incorporate the DaaS function in your code in order to call the decoder that you require.

const axios = require('axios')

async function DaaS(decoderURL, functionName, payloadToDecode, ubidotsToken)
{
var headers = {"X-Auth-Token": ubidotsToken, "Content-Type": "application/json"};

var payload =
{
"url" : decoderURL,
"payload" : payloadToDecode,
"function" : functionName
}

var options =
{
"method" : 'post',
"url" : 'http://functions.ubidots.com/pub/decode/custom',
"data" : payload,
"json" : true,
"headers" : headers,
};

const req = await axios.request(options);
return req.data.decoded;
}

4. DaaS implementation in Python

The following is a simple implementation in Python on how to make such request. You can incorporate the DaaS function in your code in order to call the decoder that you require.

def daas(decoder_url, entry_point, payload_to_decode, ubidots_token):

endpoint_url = 'http://functions.ubidots.com/pub/decode/custom'
headers = {"X-Auth-Token": ubidots_token, "Content-Type": "application/json"}
payload = {
"url": decoder_url,
"payload": payload_to_decode,
"function": entry_point
}
try:
response = requests.request('POST', endpoint_url, headers=headers, json=payload)
response.raise_for_status()
req = response.json()
return req['decoded']
except requests.exceptions.RequestException as e:
print(f"An error occurred while making the request: {e}")
return None

5. Sample decoder

We've created a dummy decoder and hosted it in this URL: https://gist.github.com/RandomGenericUsername/ed777da3346928fcdbc8ff7bb8daf922

Such decoder contains the following code, and returns an Ubidots-compatible JSON payload:

function myDecoder(args)
{
var bytes = args.bytes;
var port = args.port;
var startFlag = bytes[0];
var temperature;
var humidity;
if(startFlag != 0xAA)
{
return {"Error" : "Invalid start flag"};
}
temperature = bytes[1] << 8 | bytes[2];
humidity = bytes[3] << 8 | bytes[4];
return {"temperature" : temperature, "humidity" : humidity};

}

Now, consider a device that sends its data in a hexadecimal string with the following structure:

Byte

Description

Example

1

Start flag. Must always be 0xAA

AA

2-3

Temperature data (big endian)

0062

4-5

Humidity data (big endian)

0032

1-5

full payload

AA00620032

Let's see how this request looks like in NodeJS and Python.

Sample decoder using NodeJS

const axios = require('axios');

const ubidotsToken = 'YOUR-UBIDOTS-TOKEN';
const entryPoint = 'myDecoder';
const decoderUrl = 'https://gist.githubusercontent.com/RandomGenericUsername/ed777da3346928fcdbc8ff7bb8daf922/raw/248d5e88b3341d16ffa9e1e22e52c2a06f030545/exampleDecoder.js';

async function main(args)
{
var data = args.data;
var port = args.port;
var decoderExpectedObject = {"bytes" : Buffer.from(data, 'hex'), "port" : port};
var ubidotsPayload = await DaaS(decoderUrl, entryPoint, decoderExpectedObject, ubidotsToken);
console.log(ubidotsPayload);

//If this a UbiFunction, you need to make the request to the devices endpoint to send the data to that Device

//If this is a plugin, return an Ubidots compatible payload containing the device's data

}

async function DaaS(decoderURL, functionName, payloadToDecode, ubidotsToken)
{
var headers = {"X-Auth-Token": ubidotsToken, "Content-Type": "application/json"};

var payload =
{
"url" : decoderURL,
"payload" : payloadToDecode,
"function" : functionName
}

var options =
{
"method" : 'post',
"url" : 'http://functions.ubidots.com/pub/decode/custom',
"data" : payload,
"json" : true,
"headers" : headers,
};

const req = await axios.request(options);
return req.data.decoded;
}

The following GIF shows the simulated device sending data and using the decoder hosted on Gist:

Sample decoder using Python

import requests

decoder_url = 'https://gist.githubusercontent.com/RandomGenericUsername/ed777da3346928fcdbc8ff7bb8daf922/raw/d36303186c629d73dc3fd91c3d906e5697cd5b46/exampleDecoder.js'
entry_point = 'myDecoder'
ubidots_token = 'BBFF-ij2eOkYbTCrdrk6c7fdAxvpK7CTtVy'

def main(args):
data = args['data'] # incoming binary data
port = args['port']
decoder_expected_object = {"bytes": list(bytes.fromhex(data)), "port": port}
ubidots_payload = daas(decoder_url, entry_point, decoder_expected_object, ubidots_token)
print(ubidots_payload)
#If this a UbiFunction, you need to make the request to the devices endpoint to send the data to that Device

#If this is a plugin, return an Ubidots compatible payload containing the device's data

def daas(decoder_url, entry_point, payload_to_decode, ubidots_token):

endpoint_url = 'http://functions.ubidots.com/pub/decode/custom'
headers = {"X-Auth-Token": ubidots_token, "Content-Type": "application/json"}
payload = {
"url": decoder_url,
"payload": payload_to_decode,
"function": entry_point
}
try:
response = requests.request('POST', endpoint_url, headers=headers, json=payload)
response.raise_for_status()
req = response.json()
return req['decoded']
except requests.exceptions.RequestException as e:
print(f"An error occurred while making the request: {e}")
return None

The following GIF shows the simulated device sending data and using the decoder hosted on Gist:

6. Troubleshooting

Please keep in mind the following when using Ubidots DaaS:

  1. Identify the structure of the incoming arguments into the function/plugin. This is so you can access the incoming data. The format of the incoming arguments is usually imposed by the LNS from which the device is sending data.

    • Regarding this, for both the Python and NodeJS examples, shown below, assume that the raw binary data gets to the UbiFunction or Plugin inside the data key in the incoming function's arguments.

  2. Identify the arguments that the manufacturer decoder expects, so you can build the JSON with those same keys.

    • Regarding this, for both the Python and NodeJS examples, shown below, note that the fictitious decoder expects the bytes and port keys on its arguments, so you need to build the JSON accordingly to send to the decoder.

7. Feedback, suggestion and related articles

Feel free to post questions or suggestions in our community portal, or contact us via support@ubidots.com.


Other users also found helpful...

Did this answer your question?