Skip to content

Trigger Model

The trigger model is used to automatically invoke RPC commands after device data is processed, enabling automated control between devices. For example: when an ambient temperature change is detected, the target set temperature of an air conditioner is automatically adjusted.

Trigger logic is implemented through JavaScript scripts. Once a device is bound to a trigger model, the script runs every time a new uplink arrives. The script can call RPC commands on any target device (including itself) to perform remote control or parameter updates.

1.1. Script Runtime Environment

Trigger scripts are written as bare function bodies: your code is wrapped by the platform inside function triggerRunner() { ... } and immediately invoked, so you do not need to write your own function trigger_script(...) {...} wrapper. The script returns its result via return.

javascript
// Type just this body into the script editor — no outer function needed
let tdata = device?.telemetry_data?.[thingModelId];
if (!tdata) return null;

return {
  actions: [
    { method: "alarm", params: { _eui: device.eui, action: "new", title: "...", level: "high" } }
  ]
};

Sandbox Environment & Constraints

The trigger script runs inside a vm2 sandbox, fully isolated from the Node.js host process.

Runtime limits

ConstraintValueDetails
Execution timeout1000 msThe script is killed after 1 second; the trigger fires no actions for this cycle.
eval❌ DisabledDynamic code execution via eval is blocked.
WebAssembly❌ DisabledLoading or executing .wasm modules is blocked.
async / await❌ Not supportedTrigger scripts are synchronous; asynchronous operations are not available.
require / import❌ Not supportedNo external modules can be imported.
process, path, fs, etc.❌ Not availableThese Node.js globals are not injected; referencing them throws ReferenceError.
setTimeout / setInterval❌ Not availableTimer globals are absent. To delay execution, use the delayms field in the return value.
console❌ Not availableUse the built-in Trigger Model log feature for debugging instead.

Buffer method restrictions

The sandbox injects a restricted Buffer object (SafeBuffer). Only the following static methods are available: alloc, from, isBuffer, byteLength, compare, concat. Buffer.allocUnsafe() and Buffer.allocUnsafeSlow() are explicitly blocked. Instance read/write methods (readUInt8, writeUInt16LE, etc.) work normally.

All available sandbox globals

The following names are available directly — no import required:

NameTypeDescription
deviceObjectCurrent device object (vm.freeze, read-only).
thingModelIdStringThing Model ID bound to this device.
org_paramsObjectOrganization-level "environment variables" maintained under System Management → Server Configuration → Org Params. See Server Configuration §1.6.
envObjectEnvironment variables from plugins attached to this trigger model (apply_to=ANY or trigger). Advanced feature; most scripts do not need this.
pluginsObjectPlugin instances attached to this trigger model (same filter rule). Advanced feature; most scripts do not need this.
BufferClassRestricted SafeBuffer wrapper for binary handling (see above).
BufferTKL / PayloadParser / MSparser / Utils / TriggerHelper / RPCHelperClassAll classes exposed by tklHelper (vm.freeze, read-only). See tklHelper.

Note: device and all tklHelper classes are injected via vm.freeze. Assigning to their properties inside the script will not throw but will have no effect. The only output channel for a trigger script is its return value — the platform dispatches RPC calls based on the returned actions array.

device object properties:

PropertyTypeDescription
euistringDevice EUI (16-char hex, globally unique).
namestringDevice name.
device_typestringDevice type: "NORMAL" / "SUB_DEVICE" / "VIRTUAL".
data_fromstringData source: "LoRaWAN" or "OTHER" (direct MQTT).
parentstring | nullParent device EUI (set for SUB_DEVICE only).
onlinebooleanWhether the device is currently online.
active_timestringTimestamp of the last uplink (ISO 8601).
shared_attrsobjectAttributes synchronized bidirectionally with the device (e.g. config params, firmware info).
server_attrsobjectPlatform-side-only attributes (device cannot read). Used for alarm thresholds, linked EUIs, notification groups, etc.
mac_attrsobjectLoRaWAN MAC-layer attributes (band, ADR, etc.). Empty for non-LoRaWAN devices.
telemetry_dataobjectLatest telemetry snapshot per Thing Model, keyed by thingModelId. Use device.telemetry_data[thingModelId] to access.
thing_modelstring[]Mounted Thing Model ID array.
rpcstring[]Mounted RPC model ID array.
tagsstring[]Device tag array, used for filtering and grouping.
tenant_codestringTenant identifier.
heart_periodnumberHeartbeat detection period (seconds).

Subsequent examples in this document are still written as function trigger_script(device, thingModelId) { ... } for clarity — that form is illustrative; in the real editor you only fill in the body.

1.2. Return Value Structure

The trigger script must return either null (do nothing) or an object with the following structure:

FieldTypeDescription
delaymsNumberDelay in milliseconds before executing the actions.
abort_previous_timerBooleanIf true, any pending delayed action from a previous trigger is cancelled and replaced by this one.
should_dispatchBooleanIf true, actions are dispatched even when the data is identical to the previous trigger. Defaults to false (skipped when data is unchanged).
actionsArrayOne or more RPC calls to execute, in array order.

Each entry in the actions array:

FieldTypeDescription
_euiStringEUI of the target device that will receive the RPC call. Note: _eui lives inside params, not at the action's top level.
methodStringThe RPC Method name as defined in the RPC Model.
methodIdStringRPC Model ID — alternative to method. When both are set, methodId wins and dispatchRpcById is used; useful when method names collide across models.
paramsObject | nullInput parameters passed to the RPC script (must include _eui). If the RPC takes no other parameters, leave only _eui.

1.3. Return Value Examples

Basic control example

javascript
function trigger_script(device, thingModelId) {
    let temperature = device?.telemetry_data?.[thingModelId]?.TP;
    if (temperature === undefined) { return null; }

    if (temperature > 25) {
        return {
            delayms: 10000,
            abort_previous_timer: true,
            should_dispatch: true,
            actions: [{
                method: "mt_data_transparent",
                params: {
                    _eui: device.eui,
                    payload: "FE 05 00 00 FF 00 98 35"
                }
            }]
        };
    }
    return null;
}

Alarm trigger example (using ALARM RPC)

javascript
function trigger_script(device, thingModelId) {
    const ACTION = { no: "no", new: "new", clear: "clear" };
    const LEVEL  = { low: "low", mid: "mid", high: "high", urgent: "urgent" };

    let tdata  = device?.telemetry_data?.[thingModelId];
    if (tdata === undefined) { return null; }

    let name   = "overheat_alarm";
    let title  = "Overheat: [" + device.name + "]";
    let level  = LEVEL.high;
    let desc   = "";
    let action = ACTION.clear;
    // group is read from server_attrs; it maps to the `notify` field inside the ALARM RPC params
    let group  = device?.server_attrs?.group ?? [];

    if (tdata.temperature !== undefined && tdata.temperature >= device.server_attrs?.alarm_temp) {
        desc   = "[" + device.name + "] temperature exceeded threshold";
        action = ACTION.new;
    }

    return {
        delayms: 0,
        abort_previous_timer: true,
        actions: [{
            method: "alarm",
            params: {
                _eui:   device.eui,
                action: action,
                name:   name,
                title:  title,
                level:  level,
                desc:   desc,
                group:  group  // received as `notify` in the ALARM RPC script — see RPCModel §1.6
            }
        }]
    };
}

Note: Ensure the target device is registered on the TKL platform and has the corresponding RPC model mounted. Otherwise, the command cannot be sent.

1.4. Using TriggerHelper

TriggerHelper is a base class provided by tklHelper that simplifies building alarm-based trigger scripts. Instead of constructing the full return object manually, extend TriggerHelper and override _alarmProcess. The constructor also automatically reads device.server_attrs.notify and stores it as this.group, so alarm notifications are picked up from the device's server attributes without extra code.

Constructor Parameters

ParameterTypeDescription
deviceObjectThe current device object.
thingModelIdStringThing Model ID for accessing telemetry data.
alarmEventStringAlarm event name (unique identifier). Defaults to device.name.
titleStringAlarm title. Automatically prefixed with [device.name] : .
descStringAlarm description.
levelStringAlarm level: "low", "mid", "high", or "urgent".
actionStringInitial action: "new", "clear", or "no".

Method: alarm(info)

Calls _alarmProcess(info) (your override), then builds and returns the standard trigger return object. Returns null if the action is "no" or if _alarmProcess returns false.

Example

javascript
function trigger_script(device, thingModelId) {
    class MyAlarm extends TriggerHelper {
        _alarmProcess(info) {
            let tdata = this.tdata;
            if (tdata === undefined) { return false; }

            if (tdata.depth !== undefined && tdata.depth <= device.server_attrs?.alarm_depth) {
                this.desc   = "[" + device.name + "] depth below threshold, please check";
                this.action = "new";
            } else {
                this.action = "clear";
            }
        }
    }

    let helper = new MyAlarm({
        device:      device,
        thingModelId: thingModelId,
        alarmEvent:  "depth_alarm",
        title:       "Depth Alert",
        level:       "high"
    });

    return helper.alarm();
}

1.5. Mount Trigger Model

The created trigger model must be bound to a specific device before it takes effect.

Operation path: Maintenance → Device Management → [select target device] → Details → Trigger

Steps:

  1. On the device details page, click the Trigger tab.
  2. Click Add and select the created trigger model from the drop-down list.
  3. Multiple different trigger models can be added to the same device.

✅ A single device supports multiple trigger models, suitable for multi-condition automation scenarios.

Version History & Restore

Every time you save a trigger model, the platform records a version snapshot. Click History Versions in the editor to browse earlier versions. Each entry offers:

  • Detail — view the snapshot's content (and compare it against neighboring versions).
  • Restore — roll the current value back to that snapshot. Restoring creates a new version entry (so nothing in the history is lost) and reloads the list to the first page. A confirmation prompt notes that restoring produces a new version.

The same History Versions / Restore controls are available on the RPC Model, Thing Model, and Forwarder Script editors.