Click to download this document.
Revision History
Version | Date | Changes |
1.0 | 2026-08-14 | Initial release |
1. Overview
1.1 Scope
This guide applies to the E2C Trinity product family (E2C Factory, E2C Field, E2C Facility). Except for the "Private Protocols" module, which is supported only by E2C Factory, all script modules are identical across the three products.
Intended Audience: Users with basic JavaScript programming skills.
1.2 Script Engine
Item | Description |
Language | JavaScript (ECMAScript 5.1, with partial ES6 support) |
Execution Model | Script content is executed as a function body; each script is compiled only once |
Concurrency | The engine manages execution instances automatically; instances are not shared across tasks |
1.3 Features and Constraints
- Language Support: Supports ECMAScript 5.1, with partial ES6 support (let/const/arrow functions/template literals/destructuring/Promise, etc.). async/await is not supported.
- No DOM / BOM: No browser environment. window, document, setTimeout, fetch and other browser APIs are not available.
- No Node.js Standard Library: require(), import, fs, http and other Node.js modules are not supported. IO operations must be performed through the built-in Edge object.
- Synchronous Calls: All built-in APIs are synchronous. Scripts must also execute synchronously.
- Exception Handling: try/catch is supported. Uncaught exceptions are captured by the engine and treated as execution failures.
- State Isolation: Different business modules use independent execution environments. Global variables are not shared across modules. Within the same module, execution instances may be reused. Do not rely on global variable state across script executions. Use Edge.SetKey / Edge.GetKey to persist state across executions.
- Execution Timeout: There is no built-in timeout for individual script execution. Avoid infinite loops or long-blocking logic in scripts.
- Memory Safety: Avoid creating large closures or large objects in scripts to prevent memory growth.
1.4 Data Type Mapping
The script runtime follows these data type rules:
Type | Description |
Number | All numeric values are unified as floating-point (float64). There is no integer/float distinction. Use Math.floor() or bitwise operations for integer arithmetic |
String | UTF-8 encoded string |
Boolean | true / false |
Object | Key-value pairs, corresponding to internal system data structures |
Array | Array, corresponding to internal list structures |
Uint8Array | Byte array, used for raw frame processing in the Private Protocols module (uplink parsing input, downlink command return value) |
null | Null value, indicating no data or operation failure |
Note: Since all numeric values are unified as floating-point, large integers may lose precision. When handling integers exceeding 2^53, pass them as strings.
2. Quick Start
2.1 Accessing the Script Editor
Script functionality is embedded in each business module — no separate installation or activation is required. Access the script editor through the following paths depending on the target module:
Module | Access Path | Applicable Products |
Packet Reassembly | Data to Cloud → Add HTTP → Packet Reassembly | All |
MQTT Publish | Data to Cloud → Add MQTT → Message Management → Add Publish | All |
MQTT Subscription | Data to Cloud → Add MQTT → Message Management → Add Subscription | All |
Action Management | Scenario Management → Action Management → Execute Function | All |
Tag Change Script | Tag Management → Tag Change Script | All |
Uplink Parsing | Private Protocols → Uplink Protocol Parsing | E2C Factory only |
Downlink Command | Private Protocols → Downlink Command | E2C Factory only |
After entering the corresponding feature page, locate the script editing area in the configuration interface to write JavaScript scripts.
2.2 Writing Your First Script
Using "Data to Cloud — Normal Group Payload Transform" as an example, the following steps guide you through your first script:
Step 1: Configure a device group in Data to Cloud as the data source for cloud reporting.
Step 2: Go to "Data to Cloud", add an MQTT cloud service. Refer to the E2C Factory / E2C Field user manual for detailed configuration.
Step 3: On the MQTT service configuration page, add a Publish to enter the script editor.
Step 4: Paste the following code into the script editor:
1 var payload = msg.payload; 2 var dataList = []; 3 4 for (var key in payload) { 5 if (payload.hasOwnProperty(key)) { 6 var p = payload[key]; 7 dataList.push({ 8 name: p.tag, 9 value: parseFloat(p.value) || p.value,10 time: p.time,11 device: p.deviceName12 });13 }14 }15 16 return {17 messageId: msg.messageId,18 reportTime: msg.groupTime,19 group: msg.groupName,20 metrics: dataList21 };Step 5: Save the script configuration and ensure the MQTT cloud service status is "Enabled".
Step 6: Wait for one reporting cycle, then verify on the MQTT Broker side that the transformed data has been received. The expected JSON output should look like:
1 {2 "messageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",3 "reportTime": 1718000000000,4 "group": "workshop_A_temp_humidity",5 "metrics": [6 { "name": "temperature", "value": 25.3, "time": 1718000000000, "device": "PLC01" },7 { "name": "humidity", "value": 60.1, "time": 1718000000000, "device": "PLC01" }8 ]9 }For more examples, see Section 6.
2.3 Viewing Logs and Debugging
During script execution, logs and debug information can be viewed through the following methods:
Debug Logs (Recommended):
Use Edge.Log("your message") to output logs, view in real‑time in the "Debug Log" menu
System Log:
Use log("your message") to output to the system log, view in real‑time via the menu "System Settings‑Logs".
Debugging Tips:
- Add Edge.Log("input: " + JSON.stringify(msg)); at the script entry to confirm the input structure
- Add logs after key processing steps to trace data flow
- Add Edge.Log("output: " + JSON.stringify(result)); before returning to confirm the output
- Wrap potentially failing operations with try/catch and log exception details in the catch block
2.4 Script Lifecycle
Phase | Description |
Create | Enter the script editor from a business module configuration page to write the script |
Save | Save the script content; the script is compiled and ready |
Enable | Enable the associated business module configuration (e.g., cloud service, scenario strategy); the script starts executing based on trigger conditions |
Disable | Disable the associated business module configuration; the script stops executing |
Edit | Modify the script content and save; the new version takes effect immediately without restart |
Delete | Delete the associated business module configuration; the script is deleted along with it |
Note: Script changes take effect immediately upon save — no gateway restart required. However, modifying production scripts during low-traffic periods is recommended.
3. General Conventions
3.1 Input Parameter
- If a script accepts input, the parameter name is always msg.
- The type of msg is determined by the business module. See Section 4 for details.
- The script content itself serves as the function body. The engine automatically wraps it into a function for execution, so you can use msg directly — no need to declare a function yourself.
3.2 Return Value
- There is no enforced return type; each business module consumes the return value differently.
- Cloud publishing modules (MQTT/HTTP) serialize the return value to JSON before sending. Returning an object or array is recommended.
- Driver parsing modules (network/serial drivers) require a return value in the format { "pointName": value, ... }.
- Action management modules ignore the return value; scripts focus on side effects (writing tags, calling APIs, etc.).
- When no data modification is needed, simply return msg; — the engine will skip script execution and pass through the original data.
3.3 Logging
Scripts can output logs in two ways:
1 // Output to system log2 log("hello from script");3 4 // Publish to Debug Logs, visible in the frontend real-time log view5 Edge.Log("script executed successfully");4. Business Module Input Reference
4.1 Cloud Service — HTTP
Feature Access: Data to Cloud → Add HTTP → Packet Reassembly
Trigger: Group data is reported on cycle or on change, processed by the script, and sent to the cloud via HTTP.
Input Type: Object
Top-level Structure:
1 {2 "messageId": "uuid string",3 "messageType": "normal | speed | pkg",4 "groupName": "group_name",5 "groupTime": 1718000000000,6 "payload": "<see payload structures below>"7 }payload — Normal Tag Group (messageType = normal)
payload is an object keyed by tag name, each containing the following fields:
1 { 2 "temperature": { 3 "tag": "temperature", 4 "value": "25.3", 5 "time": 1718000000000, 6 "deviceName": "PLC01" 7 }, 8 "humidity": { 9 "tag": "humidity",10 "value": "60",11 "time": 1718000000000,12 "deviceName": "PLC01"13 }14 }If a tag has no collected value (e.g., device offline), value is null and time is 0.
payload — High-Speed Acquisition Group (messageType = speed)
High-speed groups are batched. payload is an array, each element is a snapshot frame, keyed by tag name:
1 [ 2 { 3 "temperature": { "tag": "temperature", "value": "25.1", "time": 1718000000100, "deviceName": "PLC01" }, 4 "humidity": { "tag": "humidity", "value": "60", "time": 1718000000100, "deviceName": "PLC01" } 5 }, 6 { 7 "temperature": { "tag": "temperature", "value": "25.3", "time": 1718000000200, "deviceName": "PLC01" }, 8 "humidity": { "tag": "humidity", "value": "61", "time": 1718000000200, "deviceName": "PLC01" } 9 }10 ]Each array element corresponds to one high-speed sampling snapshot and may contain multiple consecutive sampling frames.
payload — Data Table Group (messageType = pkg)
Data table groups read the most recent N records from a data table for batch reporting. payload is an array, each element is a record, keyed by field code:
1 [ 2 { 3 "field_code_1": { "tag": "field_code_1", "value": "100", "time": 1718000000000, "deviceName": "PLC01" }, 4 "field_code_2": { "tag": "field_code_2", "value": "200", "time": 1718000000000, "deviceName": "PLC01" } 5 }, 6 { 7 "field_code_1": { "tag": "field_code_1", "value": "110", "time": 1717999000000, "deviceName": "PLC01" }, 8 "field_code_2": { "tag": "field_code_2", "value": "210", "time": 1717999000000, "deviceName": "PLC01" } 9 }10 ]4.2 Cloud Service — MQTT Publish
Feature Access: Data to Cloud → Add MQTT → Message Management → Add Publish
Trigger: Group data is reported on cycle or on change, processed by the script, and published to an MQTT Broker.
Input Type: Object
Input Structure: Identical to HTTP Cloud Service. The top-level fields and the three payload types (normal / speed / pkg) share the same structure. See Section 4.1.
Note: SparkplugB protocol publishing bypasses script processing and uses the standard SparkplugB payload format directly.
4.3 Cloud Service — MQTT Subscription
Feature Access: Data to Cloud → Add MQTT → Message Management → Add Subscription
Trigger: The cloud sends a message to the device via MQTT. Upon arrival, Scenario Management (Cloud Command strategy) triggers the associated action for execution.
Input Type: string (raw MQTT payload content, received as a string in the script)
Format: No fixed format. Content is defined by the cloud side and must be parsed by the user. Typically a JSON string.
Processing Subscription Messages in Actions:
The Execute Function type action associated with the subscription-triggered strategy receives the raw MQTT payload string.
See example 6.4.
4.4 Scenario Management — Action Management (Execute Function Type)
Feature Access: Scenario Management → Action Management → Execute Function
Trigger: When a strategy is triggered (Scheduled Control, Cycle Control, Power-on Execution, Cloud Command), the associated "Execute Function" type action is executed.
Input Type: Object or null
- When triggered by Scheduled Control / Cycle Control / Power-on Execution: msg is null (no data).
- When triggered by Cloud Command: msg is the raw MQTT payload string.
4.5 Tag Change Script
Feature Access: Tag Management → Tag Change Script
Trigger: Triggered when a device tag's collected value changes (change event).
Input Type: Object
Input Structure:
1 {2 "deviceName": "PLC01",3 "tag": "temperature",4 "value": "25.3",5 "time": 17180000000006 }See example 6.6.
4.6 Private Protocols — Uplink Parsing
E2C Factory only.
Feature Access: Private Protocols → Uplink Protocol Parsing
Trigger: A device reports raw byte data, which is unpacked and passed to the script for parsing into tag key-value pairs.
Input Type: Uint8Array (unpacked raw byte frame)
Return Value: Must return an object in the format { "tagCode": value, ... }. If a non-object type is returned, the driver discards the parsing result.
See example 6.7.
4.7 Private Protocols — Downlink Command
E2C Factory only.
Feature Access: Private Protocols → Downlink Command
Downlink scripts are divided into two types with different input and return value requirements:
Acquisition Command / Heartbeat Command
Trigger: Polling drivers send acquisition commands in configured order; subscription drivers send heartbeat commands at the configured heartbeat interval.
Input: Empty string "" (no input, can be ignored)
Return Value: Must return Uint8Array. The driver writes it directly to the connection.
1 // No input; return command bytes directly2 return new Uint8Array([0x00, 0x01]);Write Command (Write Tag)
Trigger: Triggered when the system performs a write operation on a device tag.
Input Type: Array containing exactly one command object with the following fields:
Field | Type | Description |
Address | string | Tag code (must match the tag configuration) |
Value | string | Value to write (as string) |
DatatypeCode | string | Data type code |
TransactionId | int | Transaction ID, auto-incremented from 1 |
Return Value: Must return Uint8Array. The driver automatically converts and writes it to the connection. Returning other types (e.g., plain array, string) will cause conversion failure.
See example 6.7.
5. Built-in API Reference
In addition to JavaScript native functions (JSON, Math, String, Array, Date, etc.), the script runtime provides the following built-in objects and functions.
5.1 Global Functions
Signature | Description |
log(msg) | Outputs a log entry to the system log |
5.2 Edge Object
The Edge object provides interaction with system modules. All methods are synchronous.
Device Tag Read/Write
1 Edge.ReadTags(deviceName, tags) -> []{ tag, value } | nullReads the current values of multiple tags from a specified device.
- deviceName: Device name (string)
- tags: Array of tag names, e.g., ["temperature", "humidity"]
- Returns: [{ "tag": "temperature", "value": "25.3" }, ...], or null on failure or no data
1 Edge.WriteTags(deviceName, tagValues) -> boolWrites multiple tag values to a specified device.
- tagValues: [{ "tag": "pointName", "value": "val" }, ...]
- Returns: true on success, false on failure
1 Edge.WriteData(deviceName, bytes) -> boolWrites raw byte data to a specified device (for custom protocol devices).
1 Edge.ReadDataTags(tableCode, tags) -> []{ tag, value } | nullReads the latest field values from a data table (for the Data Management module).
- tableCode: Data table code
- tags: Array of field names
1 Edge.WriteDataTags(tableCode, tagValues) -> boolWrites a record to a data table.
- tagValues: [{ "tag": "fieldName", "value": "val" }, ...]
System Parameters
1 Edge.GetParam(paramName) -> { name, value } | {}Reads a system custom parameter value.
1 Edge.SetParam(paramName, value) -> boolUpdates a system custom parameter value.
Global Cache (Key-Value)
1 Edge.SetKey(key, value) -> boolStores a key-value pair in memory (process-global, lost on restart). Suitable for passing temporary state across script executions.
1 Edge.GetKey(key) -> value | nullRetrieves a value from the cache.
Logging
1 Edge.Log(content)Publishes a log message to the Debug Logs, click the Debug Log menu to view it on the page.
HTTP Requests
1 Edge.PostJson(url, head, data) -> stringSends a POST request (Content-Type: application/json), 2-second timeout.
- head: Request header object, e.g., { "Authorization": "Bearer xxx" }
- data: Request body, any object, will be serialized to JSON
- Returns: Response body string, or error message string on failure
1 Edge.GetJson(url, head) -> stringSends a GET request, 2-second timeout. Returns the response body string.
1 Edge.HttpClient(url, method, body, headParam) -> stringGeneral-purpose HTTP client, supports custom methods and parameters.
- body: Request body parameter object
- headParam: Request header object
MQTT Publishing
1 Edge.MqttPub(clientId, topic, msg) -> boolPublishes an MQTT message through a specified cloud service client.
- clientId: Cloud service Client ID (defined in system cloud service configuration)
- topic: Target Topic
- msg: Message content string
- Returns: true if published successfully (confirmed within 2 seconds), false otherwise
1 Edge.MqttResp(clientId, topic, msg) -> boolPublishes a response message through a cloud service. clientId and topic support system parameter placeholder substitution (e.g., {$deviceSn}).
File Transfer
1 Edge.DownloadFromHTTP(url, fileName, method, headParam) -> boolDownloads a file from an HTTP URL to local storage.
1 Edge.UploadFileToHTTP(url, fileName, headParam) -> boolUploads a local file to an HTTP URL.
1 Edge.DownloadFromFTP(serverAddr, username, pwd, remotePath, localFile, fileProtocol) -> boolDownloads a file from an FTP/SFTP server. fileProtocol is "ftp" or "sftp".
1 Edge.UploadToFTP(serverAddr, username, pwd, remotePath, localFile, fileProtocol) -> boolUploads a local file to an FTP/SFTP server.
1 Edge.GatewayConfigImportHTTP(url, fileName, method, headParam) -> boolDownloads a file from an HTTP URL and imports it as gateway configuration.
Encryption / Decryption
1 Edge.EncryptRSAString(publicKey, contentStr) -> stringEncrypts a string using an RSA public key. Returns the encrypted result. Returns an empty string on failure.
1 Edge.DecryptRSAString(privateKey, contentStr) -> stringDecrypts a string using an RSA private key. Returns the decrypted result. Returns an empty string on failure.
Gateway Hardware Information
1 Edge.GetGatewayInfo() -> Object | nullRetrieves gateway basic information. Return fields:
Key | Type | Description |
gatewayName | string | Gateway name |
gatewayNo | string | Gateway serial number |
deviceSn | string | Device SN |
model | string | Device model |
IMEI | string | IMEI |
IMSI | string | IMSI |
iccid | string | SIM card ICCID |
serviceProvider | string | Carrier name |
ip | string | Current uplink IP |
latitude | string | GPS latitude |
longitude | string | GPS longitude |
firmwareVersion | string | Firmware version |
appVersion | string | Application version |
1 Edge.GetSimStatus() -> Object | nullRetrieves SIM card and signal status. Return fields:
Key | Type | Description |
iccid | string | SIM card ICCID |
network | string | Network type, e.g., LTE, 5G, GSM |
lac | string | Location Area Code |
cellid | string | Base station Cell ID |
signal | string | Signal strength; CSQ value for GSM/GPRS/WCDMA, RSRP value for LTE/LTE-NB/LTE-M1/5G |
1 Edge.GetTraffic() -> Object | nullRetrieves SIM card traffic information. Return fields:
Key | Type | Description |
iccid | string | SIM card ICCID |
upperData | int64 | Uplink traffic (bytes) |
lowerData | int64 | Downlink traffic (bytes) |
totalData | int64 | Total traffic (bytes), = upperData + lowerData |
DI/DO Control
1 Edge.GetDiStatus(di) -> intReads the digital input (DI) level status. Returns 0/1, or -1 on failure.
1 Edge.GetDoStatus(do) -> intReads the current digital output (DO) status.
1 Edge.SetDoStatus(do, value) -> Object | nullSets the digital output (DO) status. value is "0" or "1".
6. Example Scripts
6.1 Cloud Service — Normal Group Payload Transform (messageType = normal)
Applicable modules: 4.1 HTTP Cloud Service / 4.2 MQTT Publish
Scenario: Normal cycle/change reporting. payload is an object keyed by tag name, each containing tag, value, time, deviceName. The script transforms it into a list format required by the cloud.
1 // msg top-level structure: 2 // { 3 // messageId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", 4 // messageType: "normal", 5 // groupName: "workshop_A_temp_humidity", 6 // groupTime: 1718000000000, 7 // payload: { 8 // "temperature": { tag: "temperature", value: "25.3", time: 1718000000000, deviceName: "PLC01" }, 9 // "humidity": { tag: "humidity", value: "60.1", time: 1718000000000, deviceName: "PLC01" }10 // }11 // }12 13 var payload = msg.payload;14 var dataList = [];15 16 // Flatten keyed payload into an array17 for (var key in payload) {18 if (payload.hasOwnProperty(key)) {19 var p = payload[key];20 dataList.push({21 name: p.tag,22 value: parseFloat(p.value) || p.value,23 time: p.time,24 device: p.deviceName25 });26 }27 }28 29 return {30 messageId: msg.messageId,31 reportTime: msg.groupTime,32 group: msg.groupName,33 metrics: dataList34 };6.2 Cloud Service — High-Speed Group Payload Transform (messageType = speed)
Applicable modules: 4.1 HTTP Cloud Service / 4.2 MQTT Publish
Scenario: High-speed acquisition. payload is an array, each element is a sampling snapshot frame (same format as a single normal entry). The script converts multiple frames into a batch reporting structure.
1 // msg top-level structure: 2 // { 3 // messageId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", 4 // messageType: "speed", 5 // groupName: "high_speed_group", 6 // groupTime: 1718000000000, 7 // payload: [ 8 // { "temperature": { tag, value, time, deviceName }, "humidity": { ... } }, 9 // { "temperature": { tag, value, time, deviceName }, "humidity": { ... } }10 // ]11 // }12 13 var payload = msg.payload;14 var frames = [];15 16 // Each element in payload is one snapshot frame17 for (var i = 0; i < payload.length; i++) {18 var frame = payload[i];19 var points = [];20 for (var key in frame) {21 if (frame.hasOwnProperty(key)) {22 points.push({23 name: key,24 value: frame[key].value,25 time: frame[key].time26 });27 }28 }29 frames.push(points);30 }31 32 return {33 messageId: msg.messageId,34 group: msg.groupName,35 frames: frames36 };6.3 Cloud Service — Data Table Group Payload Transform (messageType = pkg)
Applicable modules: 4.1 HTTP Cloud Service / 4.2 MQTT Publish
Scenario: Data table group reporting. Reads the most recent N records from a data table for batch upload. payload is an array, each element is a table record keyed by field code. The script expands it into a row-column structure required by the cloud.
1 // msg top-level structure: 2 // { 3 // messageId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", 4 // messageType: "pkg", 5 // groupName: "production_stats", 6 // groupTime: 1718000000000, 7 // payload: [ 8 // { "field_code_1": { tag, value, time, deviceName }, "field_code_2": { ... } }, 9 // { "field_code_1": { tag, value, time, deviceName }, "field_code_2": { ... } }10 // ]11 // }12 13 var payload = msg.payload;14 var records = [];15 16 // Each element in payload is one table record17 for (var i = 0; i < payload.length; i++) {18 var record = payload[i];19 var row = { _time: 0 };20 for (var key in record) {21 if (record.hasOwnProperty(key)) {22 row[key] = record[key].value;23 // Use the timestamp of the first field as the record time24 if (row._time === 0) {25 row._time = record[key].time;26 }27 }28 }29 records.push(row);30 }31 32 return {33 messageId: msg.messageId,34 group: msg.groupName,35 records: records36 };6.4 MQTT Subscription — Parse Command and Write Device Tags
Applicable modules: 4.3 MQTT Subscription / 4.4 Action Management (Cloud Command trigger)
Scenario: The cloud sends a control command (JSON) via MQTT. The subscription message is parsed, and the corresponding device tags are written. The result is replied to the cloud via MQTT.
Cloud command format:
1 {2 "command": "write",3 "deviceName": "PLC01",4 "tags": [5 { "tag": "setpoint_temp", "value": "75" },6 { "tag": "enable_fan", "value": "1" }7 ]8 } 1 // msg is the raw MQTT payload string 2 var data; 3 try { 4 data = JSON.parse(msg); 5 } catch (e) { 6 // Parse failed, log raw content 7 Edge.Log("parse error: " + e.message + " raw=" + msg); 8 return; 9 }10 11 if (data.command !== "write") {12 // Unknown command, discard13 Edge.Log("unknown command: " + data.command);14 return;15 }16 17 // Write tags to the target device18 var ok = Edge.WriteTags(data.deviceName, data.tags);19 if (ok) {20 Edge.Log("write ok device=" + data.deviceName + " count=" + data.tags.length);21 } else {22 Edge.Log("write failed device=" + data.deviceName);23 }24 25 // Reply with execution result via MQTT26 var ack = JSON.stringify({27 command: "writeAck",28 deviceName: data.deviceName,29 success: ok,30 timestamp: new Date().getTime()31 });32 Edge.MqttResp("clientId", "device/response", ack);6.5 Cycle Strategy Action — Scheduled Acquisition and Reporting
Applicable modules: 4.4 Action Management (Cycle Control / Scheduled Control / Power-on Execution trigger)
Scenario: Reads key tags from multiple devices every minute, aggregates them, and reports to a business system via HTTP POST.
1 // msg is null when triggered by cycle / scheduled / power-on strategy 2 3 var devices = ["Chiller_01", "Chiller_02", "Chiller_03"]; 4 var pointNames = ["inlet_temp", "outlet_temp", "flow_rate", "power"]; 5 6 var report = { 7 timestamp: new Date().getTime(), 8 chillers: [] 9 };10 11 for (var i = 0; i < devices.length; i++) {12 var tags = Edge.ReadTags(devices[i], pointNames);13 if (tags == null) {14 // Read failed, skip this device15 Edge.Log("read failed device=" + devices[i]);16 continue;17 }18 // Build per-device data object19 var item = { deviceName: devices[i] };20 for (var j = 0; j < tags.length; j++) {21 item[tags[j].tag] = tags[j].value;22 }23 report.chillers.push(item);24 }25 26 // Fetch API token from system params27 var token = Edge.GetParam("api_token");28 var resp = Edge.PostJson(30 { "Authorization": "Bearer " + (token ? token.value : "") },31 report32 );33 34 Edge.Log("report done resp=" + resp);6.6 Tag Change Script — Threshold-Based Linkage Control
Applicable modules: 4.5 Tag Change Script
Scenario: When a temperature tag exceeds a threshold, automatically write a control tag to turn on a fan and notify the cloud via HTTP. A debounce mechanism ensures at most one report per minute.
1 // msg: { deviceName, tag, value, time } 2 var temp = parseFloat(msg.value); 3 4 // Skip non-numeric values 5 if (isNaN(temp)) { 6 return; 7 } 8 9 var threshold = 80.0;10 11 if (temp > threshold) {12 // Turn on the cooling fan13 Edge.WriteTags(msg.deviceName, [{ tag: "fan_control", value: "1" }]);14 Edge.Log("high temp: " + temp + " >" + threshold + " fan on");15 16 // Debounce: report at most once per minute17 var lastAlarm = Edge.GetKey("fan_alarm_time");18 var now = msg.time;19 if (lastAlarm == null || (now - lastAlarm) > 60000) {20 Edge.SetKey("fan_alarm_time", now);21 // Notify the cloud platform22 Edge.PostJson("https://api.example.com/alarm", {}, {23 device: msg.deviceName,24 point: msg.tag,25 value: temp,26 time: now27 });28 }29 }6.7 Private Protocol Script — Temperature and Humidity Sensor Protocol (Uplink Parsing + Downlink Write)
Applicable modules: 4.6 Private Protocols (Uplink Parsing) / 4.7 Private Protocols (Downlink Command)
Device Protocol
Type | Frame | Description |
Request command | 00 01 | 2 bytes, read temperature and humidity |
Response frame | 00 24 00 22 | 4 bytes, bytes 1–2 = temperature, bytes 3–4 = humidity |
Write temperature | 00 03 00 00 | 4 bytes, bytes 1–2 = type, bytes 3–4 = value |
Write humidity | 00 04 00 00 | 4 bytes, bytes 1–2 = type, bytes 3–4 = value |
Tag-to-Protocol Field Mapping
Tag | Code | Protocol Bytes |
Temperature | tm | Bytes 1–2 |
Humidity | hm | Bytes 3–4 |
Uplink Parsing Script (Module 4.6)
Unpacking mode: "Fixed length 4". The device responds with a 4-byte frame. The script parses it into tag key-value pairs keyed by tag code.
1 // msg is a Uint8Array raw response frame, 4 bytes 2 // Response frame layout: 3 // [0-1] temperature (big-endian int16) 4 // [2-3] humidity (big-endian int16) 5 6 var arr = new Uint8Array(msg); 7 8 // Guard: drop short frames 9 if (arr.length < 4) {10 return { error: "invalid frame" };11 }12 13 return {14 "tm": (arr[0] << 8) | arr[1], // temperature15 "hm": (arr[2] << 8) | arr[3] // humidity16 };Downlink Write Script (Module 4.7)
When the system issues a write tag command, the script constructs the corresponding 4-byte write command frame based on the tag code. The return value must be Uint8Array.
The input msg is an array containing exactly one command object with the following fields:
Field | Type | Description |
Address | string | Tag code, e.g., "tm" / "hm" |
Value | string | Value to write (as string) |
DatatypeCode | string | Data type code |
TransactionId | int | Transaction ID |
1 // msg = [{ Address, Value, DatatypeCode, TransactionId }] 2 // Address: tag code (tm=temperature, hm=humidity) 3 // Value: value to write (string) 4 5 var cmd = msg[0]; 6 var writeVal = parseInt(cmd.Value, 10); 7 var hi = (writeVal >> 8) & 0xFF; // value high byte 8 var lo = writeVal & 0xFF; // value low byte 9 10 // Frame layout: [ type_hi, type_lo, value_hi, value_lo ]11 if (cmd.Address === "hm") {12 // Write humidity: type = 0x000213 return new Uint8Array([0x00, 0x02, hi, lo]);14 } else if (cmd.Address === "tm") {15 // Write temperature: type = 0x000316 return new Uint8Array([0x00, 0x03, hi, lo]);17 } else {18 // Unknown tag code, send no-op19 Edge.Log("unknown address: " + cmd.Address);20 return new Uint8Array([0x00, 0x00, 0x00, 0x00]);21 }7. Debugging and Troubleshooting
7.1 Common Errors
Symptom | Possible Cause | Solution |
Script not executing | Associated business module not enabled | Check the enable status of cloud service / scenario strategy |
Data not reaching cloud | Script has no return or returns undefined | Ensure the script has an explicit return statement |
Global variables lost | Execution instance reused, global state not preserved | Use Edge.SetKey() / Edge.GetKey() to persist state |
parseInt returns NaN | Input value is not a numeric string or is null | Process with parseFloat() first, or check if input is null |
async/await error | Engine does not support async/await | Use synchronous calls; all Edge APIs are synchronous |
setTimeout error | No browser environment | Remove all timer-related code |
HTTP request timeout | Built-in timeout is 2 seconds | Optimize target server response speed, or reduce data volume per request |
Private protocol parsing returns no data | Return value is not an object type | Ensure the return is an object in { "tagCode": value } format |
Downlink command send failure | Return value is not Uint8Array | Ensure new Uint8Array([...]) is returned; plain arrays are not accepted |
7.2 Debugging Workflow
- Confirm input: Add Edge.Log("input: " + JSON.stringify(msg)); at the script entry to verify the actual input structure.
- Step-by-step investigation: Add logs after key steps to locate where data goes wrong.
- Verify return value: Add Edge.Log("output: " + JSON.stringify(result)); before return to confirm the output structure.
- Exception capture: Wrap key logic with try/catch and log complete error details:
1 try {2 // your logic3 } catch (e) {4 Edge.Log("error: " + e.message + " stack: " + e.stack);5 }- Click the Debug Log menu: View all Edge.Log outputs on the frontend Debug Logs page to confirm execution order and results.
7.3 FAQ
Q: Can I use let / const in scripts?
A: Yes. The engine partially supports ES6, including let, const, arrow functions, template literals, destructuring, etc. async/await is not supported.
Q: Why do global variables disappear on the next execution?
A: Script execution instances may be reused, but global state is not guaranteed to persist across executions. Use Edge.SetKey(key, value) to store and Edge.GetKey(key) to retrieve persistent state.
Q: What is the difference between return msg; and no return?
A: return msg; means skip script processing and pass through the original data. Without a return (or return undefined), the data will not be sent to the cloud.
Q: Can scripts call external HTTP APIs?
A: Yes. Use Edge.PostJson(), Edge.GetJson(), or Edge.HttpClient() to send HTTP requests. The timeout is 2 seconds.
Q: Can scripts control gateway hardware (DI/DO)?
A: Yes. Use Edge.GetDiStatus(), Edge.GetDoStatus(), Edge.SetDoStatus() to read and control digital inputs/outputs.
Q: Do I need to restart the gateway after modifying a script?
A: No. Changes take effect immediately upon save.
Q: Can multiple scripts share variables?
A: Not directly. Different business modules use independent execution environments. To pass data across modules, use system parameters (Edge.SetParam / Edge.GetParam) as an indirect mechanism.
8. Best Practices
8.1 Error Handling
Always wrap key logic with try/catch to prevent uncaught exceptions from causing execution failures:
1 try {2 var data = JSON.parse(msg);3 // process data4 return data;5 } catch (e) {6 Edge.Log("parse error: " + e.message);7 return null;8 }8.2 Performance Tips
- Avoid large objects: Do not create large closures or objects in scripts to prevent memory growth.
- Use cache wisely: Use Edge.SetKey / Edge.GetKey to store cross-execution state, but avoid storing excessively large data.
- Avoid infinite loops: There is no built-in timeout for individual script execution. Ensure script logic can exit normally.
- Minimize HTTP requests: HTTP requests have a 2-second timeout; frequent requests will impact script response time.
8.3 Security Tips
- Do not hardcode credentials: API tokens, passwords, and other sensitive information should be stored in system parameters and read via Edge.GetParam().
- Validate external input: For MQTT subscription messages, HTTP request responses, and other external data, validate format and type before processing.
- Limit write scope: When using Edge.WriteTags(), ensure the target device and tag names are correct to avoid unintended writes.
Appendix A: Glossary
Term | Definition |
Data Point | The smallest unit of device data acquisition. Each data point corresponds to a device parameter (e.g., temperature, humidity, switch status) and includes attributes such as tag name, current value, and timestamp. |
Scenario Management | Automation rule configuration module. Triggers associated actions through strategies (Scheduled Control, Cycle Control, Power-on Execution, Data-Triggered Control, Alarm Control, Cloud Command) to enable device linkage and automation. |
Action Management | A sub-module of Scenario Management. Pre-configures frequently used action sets (execute custom JS function, variable write, DO control, etc.) that can be referenced by multiple scenario strategies, avoiding duplicate configuration and improving automation efficiency. |
Data Table Group | Organizes user-created data tables from the Data Management module as data sources for cloud reporting. Supports configurable reporting intervals and batch packaging strategies. |
Standard Polling | Collects data point values at configured polling intervals, with a minimum cycle of 1s. Each data point is collected and reported independently. |
High-Speed Sampling | High-frequency sampling mode with polling cycles below 1s, supporting minimum 50ms (50ms / 100ms / 200ms / 500ms). Multiple frames are batched and reported together, suitable for data points requiring rapid trend monitoring. |
Private Protocols | E2C Factory exclusive module. Enables users to define custom device communication protocol parsing and command construction via JavaScript scripts, facilitating integration of non-standard protocol devices. Includes Uplink Parsing and Downlink Command. |
Tag Code | An identifier used in the Private Protocols module to map device data points to protocol fields. Uplink parsing scripts return values keyed by tag code; downlink command scripts identify target data points via the Address field (tag code). |
Packet Reassembly | A script processing step in the Cloud Service module, triggered before grouped data is sent to the cloud. Allows users to transform, filter, or process the payload via script to restructure internal data formats into cloud-required formats. |
Tag Change Script | A script function automatically triggered when a device data point's collected value changes (change event). Receives the data point's acquisition data (device name, tag name, value, timestamp) as input. Commonly used for threshold-based linkage control and data filtering. |
Uplink Parsing | The uplink frame parsing function in the Private Protocols module. After a device reports raw byte data and frame unpacking is complete, the script parses the byte frame into tag key-value pairs keyed by tag code. |
Downlink Command | The downlink command function in the Private Protocols module. Includes two types: ① Acquisition/Heartbeat commands (polling drivers send cyclically, subscription drivers send at heartbeat intervals); ② Write commands (triggered by write operations on data points). Scripts return Uint8Array protocol command frames. |
Polling Driver | A driver mode for Private Protocols devices. The system sends acquisition commands cyclically in configured order, and the device responds passively. Suitable for request-response communication models. |
Subscription Driver | A driver mode for Private Protocols devices. The system sends heartbeat commands at configured intervals to maintain the connection, and the device proactively reports data. Suitable for event-driven or push-based communication models. |