Language Reference

Data Types

  • Boolean: true or false. Example: let b = true;

  • Number: 64-bit floating point number. Example: let n = 3.14;

  • String: A sequence of characters. Example: let s = "Hello";

  • Object: A collection of unordered key-value pairs. Example: let obj = {key1: "value1", key2: 2};

  • Array: An ordered list of values. Example: let arr = [1, 2, 3];

  • Function: A block of code that can be called. Example: let f = function() { return 1; };

  • Undefined: A special value representing an uninitialized variable. Example: let u;

  • Null: A special value meaning “no value”. Example: let n = null;

To check the data type of a variable, use the typeof operator. Example: typeof 3.14 returns "number".

Implicit type conversions from one type to another are not allowed. For example, the following code will throw an error: let n = 3.14 + "2";
Instead, explicitly convert types. Example: let n = 3.14 + JSON.parse("2");

Rules and Warnings

The following rules should be followed when writing scripts or a warning will be generated:
  • No unused variables or functions.

  • Always put curly braces around blocks in loops and conditionals (eg. if statements)

  • No unreachable code. Check you are not unconditionally returning from a function before the end of the function.

These rules exist to ensure the script is as efficient as possible and to prevent common programming errors.

Built-In Functions

JSON.parse(str)

Parse JSON string and return parsed value. Can also be used to convert a string to a number.

Note: if you require a fixed number of decimal places when converting from a string to a number use SQ.to_fixed()

// Convert string to a number
let n = JSON.parse("-37.165345");

// Convert JSON string to an object
let obj = JSON.parse("{key1: \"value1\"}");
let value = obj.key1;
JSON.stringify(value)
Get string representation of the mJS value or object.
Example: let s = JSON.stringify({"key1": "value1"}); returns "{\"key1\":\"value1\"}"
Example: let s = JSON.stringify(3.14); returns "3.14"
Object.create(proto)
Create an object with the provided prototype.
Example: let proto = {foo: 1}; let o = Object.create(proto);
'string'.slice(start, end)
Return a substring between two indices.
Example: 'abcdef'.slice(1,3) === 'bc';
'string'.at(index)
Return numeric byte value at given string index.
Example: 'abc'.at(0) === 0x61;
'string'.indexOf(substr[, fromIndex])
Return index of first occurrence of substr within the string or -1 if not found.
Example: 'abc'.indexOf('bc') === 1;
chr(n)
Return 1-byte string whose ASCII code is the integer n. If n is not numeric or outside of 0-255 range, null is returned.
Example: chr(0x61) === 'a';
array.splice(start, deleteCount, ...)
Change the contents of an array by removing existing elements and/or adding new elements.
Example: let a = [1,2,3,4,5]; a.splice(1, 2, 100, 101, 102); a === [1,100,101,102,4,5];
mkstr(ptrVar, length)
Create a string in a previously allocated memory chunk. The returned string starts at memory location ptrVar, and is length bytes long.
Example: let s = mkstr(ptrVar, 10);
mkstr(ptrVar, offset, length, copy = false)
Like mkstr(ptrVar, length), but the returned string starts at memory location ptrVar + offset, and the caller can specify whether the string needs to be copied to the internal mjs buffer. By default it’s not copied.
Example: let s = mkstr(ptrVar, 0, 10, true);
isNaN(value)
Return true if the value is NaN, otherwise false.
Example: isNaN(3.14) === false;

System

Required library: load('api_sys.js');

Sys.malloc(size)

Allocate a memory region and return the pointer to the memory. Memory allocated this way must be explicitly released with free().

Sys.free(ptrVar)

Free memory previously allocated with malloc.

Sys.total_ram()

Return total available RAM in bytes.

Sys.free_ram()

Return free available RAM in bytes.

Sys.reboot(ms)

Reboot the system after ms milliseconds.

Sys.uptime()

Return number of seconds since last reboot.

Sys.usleep(microseconds)

Delay execution the given number of microseconds.

Warning

No background processing will occur during Sys.usleep. Execution is blocked and the device will be unresponsive during this time.

Config

Set and get values from the device’s config.

Required library: load('api_config.js');

Cfg.get(path)
Get a value from the device’s configuration.
path: the JSON path (using dot notation) of the setting to get.
Examples:
Cfg.get('device.id');          // returns a string
Cfg.get('accel.interval');     // returns an integer
Cfg.get('ambient.available');  // returns a boolean
Cfg.set(obj)
Set part of the device’s configuration. The new value is written to the internal FLASH configuration file which persists between power cycles.
obj: the JSON object to set.
Examples:
Cfg.set({input2: {digital: {alert: {enable: false}}}});

Warning

Incorrect use of the Cfg.set() function may lead to corruption of critical parameters, and result in bricking of the device. Use with caution.

Warning

Excessive use of Cfg.Set() will wear internal FLASH memory. The FLASH memory can typically endure 100 000 write cycles.

Timers

Timers and time related functions.

Required library: load('api_timer.js');

Timer.set(milliseconds, flags, handler, userdata)
Setup timer with milliseconds timeout and handler as a callback. flags can be either 0 or Timer.REPEAT. In the latter case, the call will be repeated indefinitely (but can be cancelled with Timer.del()), otherwise it’s a one-off. Returns a numeric timer ID.

Example:

Timer.set(1000, Timer.REPEAT, function() {
  // This will repeat every second
  let s = "HELLO";
  SERIAL.write(1, s, s.length);
}, null);

Warning

Be conscious of accidentally setting repeating timers from a function that itself is repeating (for instance from SQ.set_data_handler), as you will quickly run out of memory.

Timer.del(id)
Cancel a previously installed timer with given id.

Danger

Timer.del() is dangerous if not used correctly, as it is possible to delete essential operating system timers. Use of Timer.del() is not recommended.

let timer_id = 0;   // Zero is the only safe value for an invalid timer id

// Set a one-shot timer to run in 850 milliseconds and store the id
timer_id = Timer.set(850, 0, function() {
  timer_id = 0;      // IMPORTANT!: Clear the stored id. This is not done automatically.
  ...perform some actions...
}, null);

// If you need to delete the timer before it runs, use:
Timer.del(timer_id);    // Cancel the previously set timer
timer_id = 0;           // and explicitly clear the stored id (Important!)
Timer.now()
Return current time as double value, UNIX epoch (seconds since 1970).
Timer.tzo()
Return the time zone offset in hours, including any daylight savings offset. The offset value is provided by the LTE network, so an active LTE network connection is required. Returns NaN if the offset is not available.

Example use:

let tzo = Timer.tzo();
if (!isNaN(tzo)) {
  // Do something with tzo
  SQ.dispatch(1, tzo);
}
Timer.fmt(format, time)
Formats the time time according to the strftime-like format specification format. A format reference for the strftime() function can be found here.

Example use:

let now = Timer.now();
let s = Timer.fmt("ISO8601 Time is: %FT%TZ", now);
SQ.dispatch(1, s); // Example output: "ISO8601 Time is: 2021-04-13T10:17:32Z"
Timer.parse(format, input)
Reads the input string according to the given format and returns a UNIX epoch.
Returns -1 if there is an error parsing the input.
Format options:
%m - The month number (1–12).
%M - The minute (0–59).
%H - The hour (0–23).
%d - The day of month (1–31).
%Y - The year, including century (for example, 1991).
%y - The year within century (0–99).
%S - The second (0–60).
%T - Equivalent to %H:%M:%S.

Example use:

Timer.parse("%d %m %Y %H %M %S", "06 10 2022 15 23 45");    // Returns 1665069825.0
Timer.parse("%y/%m/%d", "22/10/06");                        // Returns 1665014400.0
Timer.parse("%d.%m.%Y %T", "29.12.2018 7:05:6"));           // Returns 1546067106.0

Math

General mathematical functions.

Required library: load('api_math.js');

Math.ceil(x)
Rounds x upward, returning the smallest integral value that is not less than x.
Math.floor(x)
Rounds x downward, returning the largest integral value that is not greater than x.
Math.round(x)
Returns the integral value that is nearest to x, with halfway cases rounded away from zero.
Math.max(x, y)
Returns the larger of its arguments: either x or y. If one of the arguments is NaN, the other is returned.
Math.min(x, y)
Returns the smaller of its arguments: either x or y. If one of the arguments is NaN, the other is returned.
Math.abs(x)
Returns the absolute value of x.
Math.sqrt(x)
Returns the square root of x.
Math.exp(x)
Returns the base-e exponential function of x, which is e raised to the power x.
Math.log(x)
Returns the natural logarithm of x.
Math.pow(base, exponent)
Returns base raised to the power exponent
Math.sin(x)
Returns the sine of an angle of x radians.
Math.asin(x)
Returns the inverse sine of an angle of x radians.
Math.cos(x)
Returns the cosine of an angle of x radians.
Math.acos(x)
Returns the inverse cosine of an angle of x radians.
Math.random()
Returns a pseudo-random number from 0.0 to 1.0

Senquip

Functions for interacting with data collection and the device’s peripherals.

Required library: load('senquip.js');

Constants:
  • SQ.INFO: 10

  • SQ.ALERT: 20

  • SQ.WARNING: 30

  • SQ.ALARM: 40

  • SQ.ON: 1

  • SQ.OFF: 0

Encoding Type Constants:
  • SQ.U8 - Unsigned 8 bits.

  • SQ.S8 - Signed 8 bits.

  • SQ.U16 - Unsigned 16 bits.

  • SQ.S16 - Signed 16 bits.

  • SQ.U32 - Unsigned 32 bits.

  • SQ.S32 - Signed 32 bits.

  • SQ.FLOAT - 4 byte floating point.

  • SQ.DOUBLE - 8 byte floating point.

SQ.set_data_handler(function, userdata)
Registers a callback function that allows creation of new data parameters collected by the device.
function: A callback function, invoked when a measurement cycle is completed. The completed JSON data structure is passed to the callback function.
userdata: Some user data that is passed to the callback function. Set null if unused.
SQ.dispatch_double(index, value, precision)
Add a new double precision floating point value to the device’s data message. If called multiple times for the same index value, only the first call will be written to the outgoing data message.
index: The index of the data parameter, starting from 1.
value: The numerical value of the data to be added.
precision: The number of decimal places to send in the data message. The value must be between 0 and 8 (inclusive). 0 means no decimal places.
SQ.dispatch_string(index, string, length)
Add a new string to the device’s data message. If called multiple times for the same index value, only the first call will be written to the outgoing data message.
index: The index of the data parameter, starting from 1.
string: The string to be added. Tip: a ‘\n’ character can be used to add a new line.
length: The number of characters in the string. Maximum 2000.
SQ.dispatch_event(index, severity, message)
Add an event (alert, warning, alarm) to the device’s data message.
index: The index on the data parameter, starting from 1.
severity: The severity of the event. Should be one of SQ.INFO, SQ.ALERT, SQ.WARNING or SQ.ALARM
message: The event message string. Maximum 30 characters.
SQ.dispatch(index, value, len)
Helper function to dispatch either a number or string. If the len parameter is omitted, a default is used. The function consists of the following mJS code:
function dispatch(index, value, len) {
  if (typeof value === 'string') {
    if (typeof len === 'undefined') { len = value.length; }
    this.dispatch_string(index, value, len);
  }
  else if (typeof value === 'number') {
    if (typeof len === 'undefined') { len = 1; }
    this.dispatch_double(index, value, len);
  }
}
SQ.set_trigger_handler(function, userdata)
Registers a callback function that is called when a trigger button is activated from the Senquip Portal.
function: A callback function, invoked when a trigger button event occurs. The trigger parameter index number is passed into the callback function. For example: 5 is passed in for tp5.
userdata: Some user data that is passed to the callback function. Set null if unused.
SQ.set_output(channel, state, time_s)
Set the device’s output channel to the given state, for the given time.
channel: Output channel index. (1 for Output 1)
state: The new state of the output, the value passed should be either SQ.ON or SQ.OFF
time_s: The time to stay in the new state. Use 0 for a permanent state change. (5 = 5 seconds)
SQ.set_current(channel, state)
Set the device’s current source channel to the given state. When ON, the SRC1 or SRC2 terminal will be internally connected to 12V. The channel remains in the given state until the device goes to sleep. If the Current Loop interval is enabled, the next measurement cycle will also modify the state.
channel: Current source channel index. (1 for SRC1, 2 for SRC2)
state: The new state. The value passed should be either SQ.ON or SQ.OFF
SQ.read_analog(channel)
Read the analog input value in volts for the given channel.
channel: Analog channel index:
0: Supply Voltage
1: Input 1
2: Input 2
Returns a voltage, or NaN on error.
SQ.parse(string, start, length, base, type)
Convert a string to a number using the base given.
string: The string to parse.
start: The starting character index. (0 = the first character in the string).
length: The number of characters in the string to parse from the start position.
base: The numerical base used when parsing the string. (10 = Decimal, 16 = Hexadecimal). A special case applies when when base is (-16): the byte order will be reversed.
type: (Optional) The number type used to interpret the parsed data. This parameter should be one of the encoding type constants. Default: SQ.S64
Returns the parsed number, or 0 on error.
SQ.copy(dst_ptr, string)
Copy a string into a memory location pointer to by dst_ptr. The dst_ptr would typically be acquired by using Sys.malloc().
dst_ptr: Pointer to a block of memory.
string: The source string to copy from.
Returns the number of bytes copied from the source string.
SQ.to_fixed(number, precision)
Convert a number into a string with the given precision.
number: The number to convert.
precision: The number of decimal places in the output string.
Returns a string containing the printed number.
Example: SQ.to_fixed(245.741, 1) returns 245.7
SQ.modbus_read(channel, settings, callback, userdata)
Perform a Modbus read operation with the given settings. When the read operation is complete, the callback function is called with a value parameter. If the read was successful, the value parameter will be a number containing the read value. If the read was unsuccessful, the value parameter will be NaN. Do not call a new SQ.modbus_read() until the previous read has completed. Serial 1 must be set to ‘Modbus’ mode.
channel: Serial channel to use. (1 = Serial 1)
settings: A string containing comma separated Modbus settings. Five settings are required in the correct order: Slave Address, Function Code, Register Address, Number of Registers, and Timeout in seconds. Example: “1,3,299,1,2.5”
callback: A callback function used when modbus data has been read, or timeout reached.
userdata: Some user data that is passed to the callback function. Set null if unused.
Returns 1 if settings are valid, or a negative number on error.
SQ.encode(number, type)
Convert a number into a binary string representation of the given type.
number: The number to encode.
type: The number format to use when encoding into Big Endian binary. This parameter should be one of the encoding type constants. A negative sign in front of the type will reverse the byte order and encode into Little Endian binary.
Returns a string containing the binary representation of the given number.
Example: SQ.encode(1075, -SQ.U16) returns \x33\x04
SQ.atob(string)
Decodes and returns the base 64 encoded input string.
string: A base 64 encoded string. The maximum input string length is 256 characters.
Returns the decoded string.
SQ.split(string, separator)
Takes an input string and splits it into parts using the separator character.
string: The string to split
separator: The separator character.
Returns the split up array of strings.
Example: SQ.split('1,2,,4', ',') returns ['1', '2', undefined, '4']
SQ.crc(data, length, algorithm_id)
Calculates a CRC on the specified input data and returns the CRC as an integer. The length parameter is optional, but should be specified if data contains a null character. The algorithm_id is optional, by default the Modbus CRC16 is calculated.
data: The input string.
length: (Optional) Number of bytes of the input data to use in the calculation. Default: data.length
algorithm_id: (Optional) An integer to specify the algorithm. Default: 1 (Modbus CRC16)
Returns the CRC as an integer.
Example: SQ.crc('Hello'); returns 62327
SQ.clear_pulse_count(channel)
Reset the device’s pulse counter on the given channel to zero.
channel: Pulse channel index. (1 for Pulse 1)
SQ.hourmeter_set(channel, hours)
Set the hourmeter channel to the given number of hours.
channel: Hourmeter channel index. According to table below:
SQ.VIBRATION: Vibration Hours
SQ.SUPPLY: Supply Voltage Hours
SQ.MOVEMENT: GPS Movement Hours
SQ.DIGITAL1: Digital 1 Hours
SQ.DIGITAL2: Digital 2 Hours
SQ.DIGITAL3: Digital 3 Hours
SQ.STATE1: State 1 Hours
SQ.STATE2: State 2 Hours
SQ.STATE3: State 3 Hours
SQ.STATE4: State 4 Hours
SQ.STATE5: State 5 Hours
SQ.STATE6: State 6 Hours
SQ.HRS1: Custom Hourmeter 1. A total of 10 custom hourmeters are available. Example: to use Hourmeter 10, use SQ.HRS1 + 9
hours: The new decimal value in hours. (Example: 3.75 = 3hrs 45min)
Example: reset supply hours to zero: SQ.hourmeter_set(SQ.SUPPLY, 0);
SQ.hourmeter_update(channel, active)
For custom hourmeter use. If active is true, this function will add the number of hours since the previous update to the hourmeter channel. This function is similar to SQ.set_state however it will allow more than one state to be active at a time.
channel: Hourmeter channel index. See SQ.hourmeter_set() for valid values.
active: Boolean value. If true, the hourmeter will count the time since the previous call to SQ.hourmeter_update() (where active was previously either true or false) and add time to the hourmeter channel.
SQ.set_state(number)
Set the current state of the device. State hours are calculated based on based on how long a device stays in each state. See operation section for more info.
number: New state (0 to 6 inclusive)
SQ.distance(latitude, longitude)
Calculate the distance between the device and the given position. The device’s GPS must be enabled and it must have a valid position fix.
latitude: Latitude of given position in signed decimal format.
longitude: Longitude of given position in signed decimal format.
Returns the distance in meters or NaN on error.
Example: let meters = SQ.distance(-32.93197, 151.77883);
SQ.wifi_connected()
Returns true if the device is currently connected via WiFi.
SQ.lte_connected()
Returns true if the device is currently connected via 4G LTE.
SQ.hibernate_mode()
Returns true if the device is currently in hibernate mode.
SQ.keep_awake(seconds)
Keeps the device from sleeping for the given number of seconds. Useful for custom control logic where the device may need to occasionally stay awake outside the normal cycle.
seconds: Number of seconds to remain awake.
SQ.nvs_save(channel, value)
Save a number value to non-volatile storage (NVS). The value saved can be loaded later at any point by passing the same channel index to the SQ.nvs_load() function. The saved value will persist if the device goes to sleep or hibernate.
channel: Storage channel index. Valid values are from 1 to 50 inclusive.
value: A number to save.
SQ.nvs_load(channel)
Load and return a number from non-volatile storage (NVS) for the given channel.
channel: Storage channel index. Valid values are from 1 to 50 inclusive.
Returns the last number previously saved by SQ.nvs_save() otherwise zero. If the channel argument is out of range it will return NaN.

Note

Non Volatile Storage (NVS) is retained when the device sleeps or hibernates. However, the NVS memory is reset to zero on a physical press of the reset button or if the device enters Shutdown Mode due to power loss. The device will also save NVS memory to permanent FLASH memory every 30 minutes as a backup.

GPS

GPS.get_data()
Returns an object containing the latest internal GPS data. The GPS interval setting must be non-zero.
let gps = GPS.get_data();
// Available members of gps object:
// gps.lat - Latitude in decimal degrees
// gps.lon - Longitude in decimal degrees
// gps.hdop - Horizontal dilution of precision
// gps.altitude - Altitude in meters
// gps.cog - Course over ground in degrees
// gps.speed_km - Speed in km/h
// gps.nsat - Number of satellites in fix
GPS.fix(latitude, longitude)
Fix the GPS coordinates reported by the device to the latitude and longitude given. The GPS must be enabled in the device settings. This function can be called once at the start of the script, or at any time to change the fixed position.
latitude: Latitude to use as override in signed decimal format.
longitude: Longitude to use as override in signed decimal format.

CAN

Functions for reading/writing CAN data. All settings for the CAN interface are inherited from the device’s main configuration, and the CAN Interval setting must be non-zero.

Required library: load('senquip.js');

Constants:
  • CAN.STD: 0

  • CAN.EXT: 1

CAN.tx(channel, id, data, length, flags, repeat)
Send a CAN message with the given id, data and data length. See Examples section for usage.
channel: CAN channel to use. (1 = CAN1)
id: CAN message identifier, 29-bits for Extended CAN.
data: A string of up to 8 bytes for the message payload.
length: Number of data bytes. The valid range is 0 to 8.
flags: Message options.
CAN.STD: Standard 11-bit frame type.
CAN.EXT: Extended 29-bit frame type.
CAN.TX_SLOT(n): Transmit slot number (n) when using repeated transmits. The valid range for n is is 0 to 7.
repeat: (Optional) The interval in milliseconds to repeat the message. Default: -1 (single transmit). Use 0 to clear the repeated transmit.
Returns true on success, or false on error.

Note

Repeated CAN transmits will continue until cleared by the script or shutdown occurs. Even if the main processor is reset, the transmits will continue.

// Send a single 3-byte Extended 29-bit frame on CAN1:
CAN.tx(1, 0x18FB1055, "\x54\x82\x13", 3, CAN.EXT);

// Send a 5-byte Extended 29-bit frame, and repeat transmission every 100 milliseconds:
CAN.tx(1, 0x18FB1055, "HELLO", 5, CAN.EXT + CAN.TX_SLOT(0), 100);

// Send another 8-byte Extended 29-bit frame, and repeat transmission every 500 milliseconds:
// Slot 1 is used for the repeated message so it can co-exist with the message above (Slot 0).
CAN.tx(1, 0x18FB1055, "ABCDEFGH", 8, CAN.EXT + CAN.TX_SLOT(1), 500);

// Cancel the first repeated message in slot 0
CAN.tx(1, 0, "", 0, CAN.EXT + CAN.TX_SLOT(0), 0);

Bluetooth

Bluetooth Low Energy (BLE) functions. All settings for the BLE interface are inherited from the device’s main configuration.

Required library: load('senquip.js');

BLE.set_adv_data(data, length)
Set the raw advertising data with length. Only sets the intended payload, does not start advertising. Active advertisements must be stopped before the advertising data is updated. See Examples section for usage.
data: A string of up to 31 bytes for the raw BLE message payload.
length: Number of data bytes. The valid range is 1 to 32.
Example: BLE.set_adv_data("\x54\x82\x13", 3);

Note

This function sets the raw advertising message. If the BLE specification is not followed for bytes in the message (such as adding length and type), other devices may not correctly detect the message.

BLE.adv_enable(enable)
Stop or start BLE advertising using previously set data. Note: advertising must be stopped before the advertising data can be updated.
enable: true to start advertising broadcast, false to stop.
BLE.sq_adv(data, length)
Helper function which immediately starts advertising a ‘Manufacturer Specific’ BLE message (according to the Bluetooth Spec) using the provided data. This can be used to display information on the Senquip Connect app.
data: A string of up to 27 bytes for the ‘Manufacturer Specific’ message payload.
length: (Optional) Number of data bytes, defaults to data.length. The valid range is 1 to 27.
The helper function consists of the following code:
function sq_adv(data, len) {
  if (typeof len !== 'number') { len = data.length; }
  // Create a Manufacturer Specific message with Senquip's ID
  if (len>27) len = 27;
  let s = chr(len+3) + "\xff\x71\x0a" + data;
  this.adv_enable(false);
  this.set_adv_data(s, s.length);
  this.adv_enable(true);
}

For Bluetooth examples on how to send data to the Senquip Connect mobile app, refer to the Senquip Connect app section

Serial

Functions for reading/writing serial data over the RS232/RS485 interface. All settings for the serial port are inherited from the device’s main configuration, and the Serial 1 Interval setting must be non-zero.

Required library: load('api_serial.js');

SERIAL.write(channel, string, length, flags)
Write serial data out to the device’s RS232/RS485 port. This call can be used in all modes (Capture, Modbus and Scripted), however if a measurement cycle is active and the serial port is in use, the string data will be queued until the cycle is completed. This queue can be bypassed by using the SERIAL.IMMEDIATE flag.
channel: Serial channel index. (1 = Serial 1)
string: The string to write.
length: The number of characters in the string.
flags: (Optional) Send options. Use SERIAL.IMMEDIATE to send serial data immediately.
SERIAL.read(channel)
Read serial data from the device’s input buffer. This function is only guaranteed to work correctly when the Serial port is configured as ‘Scripting’ mode.
channel: Serial channel index. (1 = Serial 1)
SERIAL.read_avail(channel)
Return number of bytes received and waiting in the input buffer.
channel: Serial channel index. (1 = Serial 1)
SERIAL.set_handler(channel, function, userdata)
Registers a callback function that is called when there is a new data in the input buffer, however this callback function is typically not required for most applications. Serial data can be read from anywhere in a script using SERIAL.read() instead.
channel: Serial channel index. (1 = Serial 1)
function: The callback function which receives the following arguments: (channel, userdata).
userdata: Some user data that is passed to the callback function. Set null if unused.

Example:

let serial_data = "";
SERIAL.set_handler(1, function(channel) {
  // Keep adding to serial_data string as characters arrive
  serial_data = serial_data + SERIAL.read(channel);
  // Process serial_data string here
  // ...
  // Clear serial_data string when completed
  serial_data = "";
}, null);

Endpoint

Functions for sending data to custom endpoints.

Required library: load('api_endpoint.js');

MQTT.pub(topic, message, length, qos, retain)
Publish the given message on the topic for the MQTT Endpoint connection.
topic: The MQTT topic to publish on.
message: The message string to publish.
length: (Optional) The number of bytes in the message string. Default: message.length
qos: (Optional) Quality of Service value for the publish. Valid values are 0, 1 or 2. Default: 1
retain: (Optional) Retain flag for the message. Default: false
Returns the packet id if the message was successfully queued. A return value of zero indicates there was an error, or MQTT is not connected.
Example: MQTT.pub('data/topic', 'Message to publish')
MQTT.queued(packet_id)
Returns true if the given packet_id is in the MQTT output queue waiting to be sent. Note: if the device goes to sleep or the output queue overflows, queued packets will be lost. The queue can hold a maximum of 5 messages.
MQTT.is_connected()
Returns true if the MQTT connection is currently active and connected.
MQTT.sub(topic, function(conn, topic, message), userdata)
Subscribe to the given topic using the MQTT Endpoint connection and call given handler function when a message is published to the topic.
QoS is fixed at 1
topic: The MQTT topic to subscribe to.
function: Callback function with the following arguments:
conn: MQTT connection identifier.
topic: The MQTT topic.
message: The message data published to the topic.
userdata: Some user data that is passed to the callback function. Set null if unused.

Example use:

MQTT.sub('test/topic', function(conn, topic, msg) {
 // Use the msg to trigger events
 if (msg === 'OUTPUT_ON') {
   // Set output ON here
 }
}, null);
MQTT.set_lwt(topic, message, retain)
Configure the Last Will and Testament (LWT) message for the MQTT Endpoint connection.
Note: Calling this function will disconnect the MQTT connection, and reconnect with the new parameters. It is therefore recommended to call this function once at the start of a script.
topic: The MQTT topic for the LWT message.
message: The LWT message to publish.
retain: The retain flag for the LWT message. Either: true or false.

HTTP.post(body, headers)
Publish the body and extra headers in a HTTP POST request to the url specified in the HTTP Endpoint settings. HTTP must be enabled and have a valid URL in the device’s endpoint settings.
body: The data string to put in the message body. The data string should not contain binary data or the string length may be detected incorrectly.
headers: (Optional) A string of extra HTTP Headers. Each header must end with \r\n.
Returns: 1 on success, -1 on failure, 0 while in progress.
Example: let result = HTTP.post('Hello World!', 'Content-Type: text/plain\r\n')

Warning

  • Custom HTTP POST requests from the script are not retried or buffered if they fail.

  • Each HTTP.post() call consumes memory while active and could take up to 60 seconds to complete depending on the network conditions. It is recommended to only create a single active HTTP request at a time, or the device will run out of memory and crash. MQTT is the preferred method for sending data at 60 second intervals or less, as it maintains a single active connection.

HTTP.post_count()
Returns the number of active HTTP connections as a number.
HTTP.query(options)
Send a HTTP GET or POST request to the url provided and process the response. If the data option is provided the request is a POST, otherwise GET. The options object can contain the following members:
url: (Required) The URL to send the request to.
ca_cert: (Optional) Filename of CA certificate to use for SSL verification. If not provided, the default CA certificate is used. Refer to App Note APN0022 for more information on how to use a custom CA certificate.
headers: (Optional) An object containing the HTTP headers to send with the request as key/value pairs. Example {‘Content-Type’: ‘application/json’}
data: (Optional) An string or object for the body of the request. If data is provided the request becomes a POST request. If data is an object it is automatically JSON-encoded.
success: (Optional) A callback function to be called when the request is successful, containing the body response. Note the body string is heap allocated and will not persist after the callback function returns. Example callback function: function(body, full_http_msg) { }
error: (Optional) A callback function to be called when the request fails. Example callback function: function(err) { }

UDP.send(data, length)
Send the data in a UDP message to the url specified in the UDP Endpoint settings.
data: The data string to put in the message.
length: (Optional) Number of bytes of data to send. Default: data.length
Example: UDP.send('Hello World!')

Files

Functions for reading/writing files on the device. The filesystem is SPIFFS.

Required library: load('api_file.js');

File.write(string, filename, mode)
Write string data to a file on the device. If the file does not exist, it is created. The mode parameter specifies if existing data should be deleted or appended to.
string: The string to write.
filename: The file name to write to. Allowed special characters: ._-()
mode: (Optional) File mode. ‘w’: previous content is deleted. ‘a’: append to existing content. Default: ‘w’.
Returns: number of bytes written, or zero on error.
Example: let bytes = File.write('Hello World!', 'test.csv', 'a')

Warning

Excessive use of File.write() will wear internal FLASH memory. The FLASH memory can typically endure 100 000 write cycles.

File.read(filename)
Read from a file on the device and return the whole file as a string. If the file does not exist an empty string is returned.
filename: The file name to read from.
Returns: contents of the file as a string.
Example: let file_data = File.read('test.csv')

Warning

Reading large files may fail if the device is low on RAM, as the entire file is placed into device memory as a string.

File.remove(filename)
Remove a file on the device.
filename: The file name to remove.
Returns: 0 on success, non-0 on failure.
File.rename(old, new)
Rename file old to new.
old: Old file name to change.
new: The new file name.
Returns: 0 on success, non-0 on failure.

Device to Device API

Each device can request and receive data from another Senquip device, enabling advanced edge decision making based on data from multiple devices. Any Senquip device can request data from another via the Senquip Portal. Both devices must be on a Hosted plan and connected to the Senquip Portal.

Permissions must first be granted on the remote device. If Device A wishes to request data from Device B, then Device B must first grant permissions. This is using the Config –> API Settings page on Device B, where the Device ID of Device A is added to the ‘Remote Access’ list. The requester (Device A) does not require any special settings.

Device to Device API Settings

Device to Device API Settings

Required library: load('senquip.js');

SQ.set_remote_handler(function, userdata) | Registers a callback function that enables processing data from another Senquip device. This operates identically to SQ.set_data_handler() but instead receives measurement data from another device. | function: A callback function, invoked when a measurement cycle is completed. The completed JSON data structure is passed to the callback function. | userdata: Some user data that is passed to the callback function. Set null if unused.

SQ.req_remote_data(deviceid) | Request data from the given deviceid. The remote device must have granted permissions to the requesting device. The data will be sent to the requesting device’s SQ.set_remote_handler() callback function. The minimum allowed time between two requests is 30 seconds. | deviceid: A string containing the Device ID to request data from. Example: “ABC123DEF”

Refer to the examples section for a full example.