WebSocket 客户端驱动
该驱动会为每个模型建立一个连接, 驱动启动后主动建立连接并接收服务端发送的数据, 同时也可以向客户端发送数据.
脚本说明
脚本语言: JavasScript ECMAScript 5.1
驱动使用时要求提供 连接处理脚本
, 解析处理脚本
, 指令处理脚本
和 心跳处理脚本
4 个脚本函数来处理接收和发送数据过程中的协议和数据格式问题.
在脚本的上下文中内置了 Buffer
包, 可用于处理接收或发送二进制数据.
除此之外, 还内置了 lodash
, crypto-js
, moment
, xml-js
和 formulajs(Excel函数)
包.
注: 所有的脚本的函数名必须为
handler
.
客户端对象
在每次脚本中的参数中提供了 client
对象, 该对象为当前 WebSocket
连接客户端对象,
可以通过该对象实现向客户端发送数据的功能.
例如: 向客户端发送 ack
信息等. 该对象提供了以下函数:
send(Buffer)
用于向客户端发送数据.
例如: 在接收到数据时向客户端发送 ack
信息.
参数说明
参数名 | 参数类型 | 参数说明 | 示例值 |
---|---|---|---|
buffer | Buffer | 要发送的内容 | Buffer.from("hello") 表示要发送 "hello" |
注: 参数必须为
Buffer
类型.
返回值
string
或 undefined
如果参数不正确(字节数组为空或空数组)或发送失败则返回 string
内容为错误说明, 如果发送成功则返回 undefined
.
连接处理脚本
当连接状态发生变化时会调用该函数. 例如: 当连接建立时向服务端发送数据.
说明:
- 当连接断开时, 会调用该函数, 此时
state
的值为false
, 此时无法通过client
发送数据.- 当驱动启动或者重连建立连接时, 会调用该函数, 此时
state
的值为true
.- 当重启驱动时, 该函数会调用两次, 第一次
state
的值为false
, 第二次为true
.
函数定义如下:
function handler(client, state) {
// ...
}
参数说明
参数名 | 参数类型 | 参数说明 |
---|---|---|
client | object | 客户端连接对象 |
state | bool | 当前连接状态, true: 表示连接已建立, false: 表示连接已断开 |
返回值说明
无
示例
// 在连接建立后向服务端发送 "hello" 数据
function handler(client, state) {
// 连接已建立
if (state) {
client.send(Buffer.from("hello"));
}
}
数据处理脚本
该脚本用于处理从服务端接收到的数据, 然后将数据解析为平台规定的格式并返回.
函数定义如下:
function handler(client, data) {
// 数据包处理逻辑
// 返回结果必须为数组, 数组中每个元素为一个设备的实时数据信息
return [
{
"id": "d01", // 设备标识
"time": 1665999863637, // 数据采集时间(ms), unix 时间戳
"values": {"key1": "str", "key2": 123} // 数据点, key 为数据点的标识, value: 为数据点的值
}
];
}
参数说明
参数名 | 参数类型 | 参数说明 |
---|---|---|
client | object | 客户端连接对象 |
data | Buffer | Buffer 对象 |
返回值
参数名 | 参数类型 | 参数说明 | 示例值 |
---|---|---|---|
array[object] | 对象数组 | 返回值 | [{"id":"d01","time":1665999863637,"values":{"temperature":17.5,"humidity":35.7}}] |
id | 字符串 | 资产编号或设备标识 | d01 |
time | 数值 | 时间戳(ms) | 1664256913000 |
values | 对象 | 数据点信息 | {"temperature":17.5,"humidity":35.7} |
key | 字符串 | 数据点标识 | "temperature" |
value | any | 数据点的值 | 17.5 |
示例
function handler(client, data) {
// 以 json 格式为例, 例如: {"id":"d01","time":"2022-10-17 17:57:32","values":[{"name":"temperature","data":17.5},{"name":"humidity","data":35.7}]}
// 将 data 解析为 json 对象
const jsonData = JSON.parse(data.toString());
// 从对象中提取时间信息
const time = moment(jsonData.time, "YYYY-MM-DD HH:mm:ss");
// 将 values 字段解析为平台规定的格式 {"key1": value1, "key2": "value2", ...}
const values = {};
for (let i = 0; i < jsonData.values.length; i++) {
const value = jsonData.values[i];
values[value.name] = value.data;
}
// 返回解析后的结果数据
return [
{id: jsonData.id, values: values, time: time.valueOf()}
]
}
指令处理脚本
该脚本用于将发送的指令内容转换为字节数组, 当向设备发送指令时, 驱动会将要发送的内容先经过 handler
函数处理,
返回结果作为实际发送的内容.
函数定义如下:
function handler(client, data) {
// 数据转换处理, 将待发送内容转换为字节数组
// 返回结果必须为 Buffer 对象
return Buffer.from("hello"); // 表示发送 "hello"
}
参数说明
参数名 | 参数类型 | 参数说明 |
---|---|---|
client | object | 客户端连接对象 |
data | object | 指令信息, 格式如下 |
指令格式如下:
{
"name": "test",
"showName": "测试",
"ops": [
{
"value": "123"
}
],
"params": {
"test": "123"
},
"defaultValue": {
"test": "123"
}
}
字段名 | 参数类型 | 参数说明 |
---|---|---|
name | 字符串 | 指令名称 |
showName | 字符串 | 指令显示名称 |
ops.value | 字符串 | 指令中配置的发送内容 |
params | 对象 | 数据写入配置 |
defaultValue | 对象 | 数据写入配置中各字段的默认值 |
注:
ops.value
通常为实际发送的内容, 该字段为必填值.opts
为数组, 目前长度固定为 1.
返回值
参数名 | 参数类型 | 参数说明 | 示例值 |
---|---|---|---|
object | 对象 | 返回值 | {"messageType":1, "data": Buffer.from("hello")} |
messageType | 数值 | 消息类型 | 1: 文本消息, 2: 二进制消息 |
data | Buffer | 发送内容 | Buffer.from("hello") |
示例
// 发送文本消息
function handler(client, data) {
// 从指令信息中取出要发送的内容, 格式为 base64
const value = data.ops[0].value;
// 将要发送的内容做 base64 解码
return {"messageType": 1, "data": Buffer.from(value, 'hex')};
}
心跳处理脚本
心跳处理脚本用于定义驱动发送心跳时携带的数据内容, 如果无返回值或返回 undefined
表明发送心跳时不携带任何内容.
当开启心跳功能时, 驱动会定时向服务端发送心跳. 当超过设定的时间内未接收到服务端的心跳响应时会判定为连接不可用, 此时驱动断开连接并尝试重新建立建接.
函数定义
function handler(client) {
// 返回要携带的数据或者 undefined
return Buffer.from("ping");
}
参数说明
参数名 | 参数类型 | 参数说明 |
---|---|---|
client | object | 客户端连接对象 |
返回值说明
参数名 | 参数类型 | 参数说明 | 示例值 |
---|---|---|---|
buffer | Buffer | 要发送的内容 | Buffer.from("hello") 表示要发送 "hello" |
示例
// 发送心跳时携带自定义数据 "hello"
function handler(client) {
return Buffer.from("hello");
}
// 发送心跳时不携带数据
function handler(client) {
}