Scripting

This page describes avialable functionalities and features for script running

Akenza provides the possibility to run scripts as part of a data flow in order to decode data sent by devices and turn it into an actionable and human readable format (uplink decoder) or encode data that is used to send commands to devices (downlink encoder). Scripts are part of device types and are either taken from the device type library or can be created with Custom Device Types.

The scripts support JavaScript using the ECMAScript 2020 (ES 11) standard in strict mode. The scripts are plain JavaScript and every JavaScript and ES 11 functionality can be used. However, there are certain restrictions which are listed below. Importantly, loading of node.js modules and other files is disabled.

When creating a custom Device Type, the script can be executed and debugged allowing for easy development of a script. The script can also be executed by calling the API directly (more information below).

Required Script Structure

A script has to implement the function consume(object) which takes an event object as argument. An error will be returned if the script doesn't implement a consume(event) function.

function consume(event) {
emit('sample', { data: {}, topic: 'default' });
}

The consume(event) function is the entry point for the script and will be invoked upon execution. Each execution loads the script again, resetting any variable values which were set in previous runs.

The uplink event object differs slightly based on connectivity but share the same base structure. Every event contains the following structure:

{
"data": {
// the data sent in the uplink request
},
"device": {
// device properties
},
"uplinkMetrics": {
// info about the uplink
}
}

Example HTTP or MQTT event

The data object contains everything which was sent in the request body of the uplink request.

{
"data": {
"temperature": 12.4,
"humidty": 85,
...
},
"device": {
"id": "string", // the akenza id
"deviceId": "string", // the device id
"name": "string",
"description": "string"
},
"uplinkMetrics": { // meta information about the uplink forwarded by the carrier
"deviceId": "string", // the device id
"uplinkSize": 223, // recieved uplink size in bytes
"timestamp": "iso-8601-date-string", // time when the uplink was received at akenza
}
}

Example LoRaWAN event

The contents of the uplinkMetrics object differs depending on the network provider.

{
"data": {
"port": 2, // the port specified in the LoRaWAN uplink
"payloadHex": "aabbcc112233" // the hex string sent by the device
},
"device": {
"id": "string", // the akenza id
"deviceId": "string", // the device id
"name": "string",
"description": "string"
},
"uplinkMetrics": { // meta information about the uplink forwarded by the network provider
"deviceId": "string", // the device id
"uplinkSize": 223, // recieved uplink size in bytes
"timestamp": "iso-8601-date-string", // time when the uplink was sent by the device
"latitude": 46.928403,
"longitude": 7.628662,
"port": 2,
"frameCountUp": 14,
"frameCountDown": 1,
"rssi": -88.0,
"snr": 7.75,
"sf": 7,
"txPower": 8.0,
"numberOfGateways": 2,
"esp": -88.67,
"sqi": 3,
}
}

When processing an array uplink, the structure is slighly different to other events. The data object contains a single property values which contains the original array sent in the uplink.

{
"data": {
"values": [
{
"temperature": 12.4,
"humidty": 85,
...
},
...
]
},
"device": {
...
},
"uplinkMetrics": { // meta information about the uplink forwarded by the carrier
...
}
}

Emit Function

The emit('string', object) function is used to publish data back to the system, e.g. the generated sample which should be stored in the database or forwarded to a 3rd party system using an output connector. If the emit function is never called in a script, the script just runs through without any effects and no error is thrown.

Any of the following emit types can be used multiple times throughout script.

  • sample (only for uplink decoders of a device type)

  • log

  • downlink (only for downlink encoders of a device type)

There is no limit for how often the emit function is invoked during script run.

sample

If the emit function is invoked with sample as first argument, the second argument will be forwarded to the output connector

The object needs to contain the following structure:

{
"data": {
// the generated sample during the script run
},
"meta": {
// optional, can contain meta info about value calculation or similar
},
"topic": "string" // the topic of the sample
}

If the object does not follow the above structure, an error will occur during forwarding the sample to the output connector.

If the emit function is invoked with downlink as first argument, the second argument will be sent back to the device. The resulting object needs to follow a strict convention and is explained in more detail in the Downlink page.

log

If the emit function is invoked with log as first argument, the second argument will be emitted as a log object. Log objects are only displayed when developing the script in the Akenza UI. They are otherwise omitted and won't be processed any further.

Utility Functions

Akenza provides a utility module for e.g. converting hex strings into bits and vice-versa. Available functions are:

  • hexToBits('hex-string') -> returns a string of bits

  • bitsToHex('bit-string') -> returns a hex string

  • base64ToBits('base64-string') -> returns a string of bits

  • bitsToBase64('bit-string') -> returns a base64 encoded string

  • bitsToSigned('bit-string') -> returns a signed number

  • bitsToUnsigned('bit-string') -> returns an unsigned number

  • numberToBits(123) -> returns a string of bits

The above functions can be invoked using Bits. as prefix, e.g. Bits.hexToBits('0x29A') will result in the output string '1010011010'. The hex string does not necessarily need to be prefixed with 0x, any valid hex string can be passed as an argument.

Disabled Functionality

There are certain restrictions when it comes to Scripting and not every JavaScript functionality is available during script running:

  • invoking any of the console or print functions, use emit('log', object) instead

  • javascript syntax extensions

  • any file loading functionality

One Time Script Running

post
Run Script

https://api.akenza.io/v3/run-script
Scripts can be executed once without any further processing by calling an endpoint of the akenza API. Invocations of the emit('string', object) function have no further impact and are instead returned in the response body.
Request
Response
Request
Headers
x-api-key
required
string
api key required for authentication
Body Parameters
script
required
string
the script to be processed
event
required
string
the event to process
Response
200: OK
[
{
"type": "SAMPLE",
"event": {
"data": {
"tmp": 24.5
}
}
},
{
"type": "ERROR",
"event": {
"message": "invalid emit type foo"
}
},
{
"type": "LOG",
"event": {
"data": {
"tmp": 24.5
}
}
}
]

In the above request the following script is used

function consume(event) {
emit('sample', {data: {tmp: event.data.temperature}});
emit('foo', {data: event.foo});
emit('log', {tmp: event.data.temperature});
}

And the following event

{
"data": {
"temperature": 24.5
},
"timestamp": "2020-09-07T18:20:05.199Z"
}

Which produces the output as seen in the response of the example. The type reflects the emit type used to invoke the emit('string', object) function. The resulting event contains whatever was passed as second argument. In case of errors during runtime of the script, the event contains a message property detailing the error.