设备接入-TCP Server驱动设备接入
-
TCP Server 驱动 v3.2
该驱动内置了一个 tcp server 服务, 驱动启动后可以接收客户端的连接和数据, 同时也可以向客户端发送数据. 如果使用容器部署时, 需要将 tcp 服务端口开放.
注: 每个驱动实例只能添加一个模型
配置说明
以下内容为 tcp-server 驱动的配置项
数据处理流程说明
-
当接收到客户端发送的数据时, 会读取所有的发送数据并存放到 Buffer 中, 然后调用 数据包拆分脚本
-
列表数据包拆分脚本 从 Buffer 中提取完整的数据包信息或.
脚本说明
脚本语言: JavasScript ECMAScript 5.1驱动使用时要求提供 数据包拆分脚本, 数据处理脚本 和 指令处理脚本 3 个脚本函数来处理接收和发送数据过程中的协议和数据格式问题.
在脚本的上下文中内置了 Buffer 包, 可用于处理接收或发送二进制数据.
除此之外, 还内置了 lodash, crypto-js, moment, xml-js 和 formulajs(Excel函数) 包.
注: 所有的脚本函数名必须为 **handler**
客户端对象
在 数据包拆分脚本, 数据处理脚本, 指令处理脚本 和 连接处理脚本 函数的参数中提供了 client 对象, 该对象为当前 TCP 连接客户端对象, 可以通过该对象实现向客户端发送数据的功能. 例如: 向客户端发送 ack 信息等.
该对象提供了以下函数:
register
用于注册设备. 接收到客户端发送的设备注册信息时, 在脚本函数中通过调用 client 对象中的 register 函数注册该设备, 驱动会将该设备与当前连接绑定. 当需要向设备发送指令时, 会通过该绑定关系向对应的连接发送数据. 如果协议未定义设备注册, 会向上次接收到该设备数据的连接发送. 详细信息见 设备与连接绑定关系说明参数说明
返回值string 或 undefined 如果参数不正确、部分设备标识错误或对应的设备不存在时返回 string, 内容为错误说明. 如果所有设备注册成功, 返回 undefined
示例
unregister
用于注销设备. 注销设备与连接的绑定关系, 参数及返回值说明同 register示例
send
用于向客户端发送数据. 例如: 在接收到数据时向客户端发送 ack 信息.参数说明
返回值
string 或 undefined 如果参数不正确(字节数组为空或空数组)或发送失败则返回 string 内容为错误说明, 如果发送成功则返回 undefined.
示例
getRemoteAddr
用于获取客户端地址信息.参数说明
无
返回值
string. 格式: IP:Port. 例如: 192.0.2.1:25
示例
getRemoteIp
用于获取客户端 IP 地址信息.
参数说明
无返回值
string. 例如: 192.0.2.1
示例
reportCommand
上报指令执行结果. 有些场景指令的执行结果反馈是异步的, 在指令发送后, 过一段时间才会收到响应报文, 此时可以在接收到响应报文时通过 client.reportCommand(...) 方法上报指令执行结果.参数说明
注: serialNo 为平台在发送指令时生成, 会传入到 指令处理脚本 中, 当指令执行结果为异步反馈时, 可以将 serialNo 保存到 设备上下文 中, 以便在后续 reportCommand 使用
返回值
string 或 undefined. 如果返回 undefined 则表示发送成功, 否则返回数据为错误原因.
示例
getMediaFile
请求媒体库文件参数说明
返回值
示例
getMediaFileByURL
请求媒体库文件参数说明
返回值
示例
uploadMediaFile
上传文件到媒体库参数说明
返回值
示例
deleteMediaFile
删除媒体库文件参数说明
返回值
示例
saveWorkTableRow
向工作表写入一条数据参数说明
返回值
示例
updateWorkTableRow
更新工作表中的数据updateNodeById
根据资产标识更新资产数据
getContext
用于获取上下文对象, 可以在上下文中存储数据. 详细信息注: 第一次调用的时候才会创建上下文
getDeviceContext
用于获取设备上下文对象, 使用设备标识作为上下文标识, 可以在上下文中存储数据. 详细信息与 getContext 不同的是, 当设备被删除后, 重启驱动时会自动清理被删除设备的上下文对象.
注: 第一次调用的时候才会创建上下文
removeContext
删除上下文对象
removeDeviceContext
删除设备上下文对象
getContextIds
获取全部上下文标识(不包含设备上下文)
getDeviceContextIds
获取全部设备上下文标识(只包含设备上下文)
context
上下文对象, 用来存储数据, 上下文中的数据可以在不同的脚本中共享. 例如: 可以在 指令处理脚本中 写入数据, 然后从 数据处理脚本 中读取数据. 不同上下文彼此独立, 互不影响.注: 可以根据需求创建多个上下文对象, 但是上下文对象以及上下文中的数据需要及时清理, 否则会造成 **OOM** 问题, 导致驱动程序崩溃.
put
用于向上下文中存储数据.注: 存入的数据需要自行清理, 否则可能导致 OOM 等问题.
containsKey
判断上下文中是否存在指定的 key
get
从上下文中获取指定的 key 对应的数据. 如果 key 不存在则返回 undefined
getAndRemove
从上下文中获取指定的 key 对应的数据并且在返回后 删除 该 key. 如果 key 不存在则返回 undefined.注: 该函数返回后, 再使用 get 或 getAndRemove 均返回 undefined.
remove
从上下文中删除指定的 key, 如果 key 不存在则不执行任何操作.
内置函数
crc 校验
驱动中内置了 crc 对象, 可以在脚本中直接使用 crc 对象中的校验函数.- 使用 checksum16 实现 crc16 校验
- 使用 checksum32 实现 crc32 校验
- 使用 checksum64 实现 crc64 校验
- 使用 checksumModbus 实现 modbus 协议 crc 校验
modbus 校验为 crc16, 所以校验码类型为 uint16. 另外, checksumModbus 不需要 poly 多项式参数.
数据包拆分脚本
该脚本用于处理接收数据过程中的半包和粘包问题, 该函数需要根据协议和数据格式判断接收到的字节数组中是否包含完整的数据包, 如果包含了完整数据包则返回完据包的起始位置和长度. 或者当数据包有错误时丢掉该数据包或有问题部分的数据.
如果字节数组中不包含完整的数据包, 直接返回 undefined 表示需要从客户端接收更多的数据.
函数定义如下:
参数说明
返回值说明- 当字节数组中包含完整数据包时, 返回包含 package 字段的对象.
- 如果字节数组中存在错误, 则返回包含 drop 字段的对象, 丢弃掉错误的数据.
- 如果字节数组中即不包含完整的数据包也不存在错误, 直接返回 undefined, 表示需要从客户端接收更多的数据. | 参数名 | 参数类型 | 参数说明 | 示例值 | | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------- | ---------------------------------------- | | package | object | 数据包信息, 如果要丢弃数据该字段不需要返回 | {"start": 0, "length": 128, "next": 129} | | start | 数值 | 数据包在 data | | 中的起始位置 | 4 表示第 5 个字节为数据包的起始位置 | | length | 数值 | 数据包的长度, 表示从 start | | 后多少个字节为一个完整的数据包 | start=4, length=128 表示从第 5 个字节开始(包括第 5 个字节)连续 128 个字节为一个完整的数据包 | | next | 数值 | 下一个数据包的起始位置 | 例如: 在使用 \r\n | | 作为数据包间的固定分隔符时, 下一个数据包的起始位置应该为 start + length + 2 | | drop | 数值 | 要丢弃的字节数量, 即丢弃字节数组中 data[0:drop] | | 内容 | 128 表示丢弃前 128 个字节. 一般用于数据包错误时丢弃掉错误的数据包场景 |
正常接收数据
当数据包拆分脚本返回以下内容时, 表示已接收到的数据中包含了完整的数据包. 该数据包在所有数据中的起始位置为 0, 长度为 128, 下一个数据包的起始位置为 129例如, 使用 \r\n 作为数据包间的分隔符, 以解析该数据时 {"a":1,"b":2}\r\n{"a":3,"b":4}\r\n, 拆分结果为 {"package":{"start":0,"length":13,"next":15}}. 此时, 数据处理脚本 中接收到的数据为 {"a":1,"b":2}, 并不会包含 \r\n, 而下一次数据拆分脚本接收到的数据为 {"a":3,"b":4}\r\n.
包含错误或不完整数据包时
返回以下内容时, 表示接收到的数据不完整, 需要丢弃 0 - 12 部分内容.
例如, 接收到的内容为 :1,"b":2}\r\n{"a":3,"b":4}\r\n 时, :1,"b":2}\r\n 为不完整的数据包需要丢弃, 则需要返回 {"drop":11}. 下一次数据拆分脚本接收到的数据为 {"a":3,"b":4}\r\n不包含完整的数据包和错误包时
例如, 接收到的数据为 {"a":1, 未找到分隔符 \r\n, 此时返回 undefined 表示需要接收更多的数据. 当客户端发送 "b":2}\r\n{"a":3,"b":4}\r\n 数据时, 会再次调用 数据包拆分脚本, 此时 Buffer 中的数据为 {"a":1,"b":2}\r\n{"a":3,"b":4}\r\n, 此时可以提取出完整的数据包.注: 如果返回结果中同时包含了 drop 和 package 字段并且 drop 的值大于 0 时, 只做丢弃数据处理.
示例
驱动内置数据包拆包函数- 固定长度头 该函数会取前 N 个字节作为长度信息, 然后根据长度信息读取主体内容. +--------+-----------+ | Length | Data | +--------+-----------+
在数据包拆分脚本中直接使用内置的拆分函数, 如下所示:
- 固定分隔符 该函数会使用固定分隔符拆分数据包. 使用方式如下所示:
- 固定开始和结束符 该函数会读取指定开始符和结束符之间的数据做为一个完整的数据包. 使用方式如下所示:
数据处理脚本
该脚本用于处理 数据包拆分脚本 函数解析得到的完整数据包, 根据协议和数据格式将数据包解析为平台定义的数据格式.函数定义如下:
参数说明
返回值
注: 返回值必须为 **Object[]** 或 **undefined** 其中之一. 返回空数组表示未从接收到的数据中解析出有效数据, **undefined**表示无返回结果, 驱动程序无须处理返回结果. 例如: 接收到的数据为心跳数据, 不包含采集数据.
示例
指令处理脚本
该脚本用于将发送的指令内容转换为字节数组, 当向设备发送指令时, 驱动会将要发送的内容先经过 命令处理脚本 函数处理, 返回结果作为实际发送的内容.
函数定义如下:
参数说明
指令格式如下:以 test 指令为例
注: ops.value 通常为实际发送的内容, 该字段为必填值. opts 为数组, 目前长度固定为 1. 当要发送的数据内容比较复杂时, 可以先转发送内容转换为 base64 格式的字符串, 然后在在指令脚本中再进行 base64 解码后再发送.
返回值说明
必须值必须为 Buffer 对象.
注: 可以使用 Buffer.from("this is a string"") 等方法创建 Buffer 对象. 关于 Buffer 的使用说明可以点击查看
示例
连接处理脚本
当客户端连接到驱动或断开时, 会调用 连接处理脚本.函数定义如下:
参数说明
返回值说明
无返回值
示例
设备与连接绑定关系说明
设备与连接关系绑定, 主要用于向设备发送指令时, 驱动会根据该绑定关系确认通过哪个连接发送指令数据. 绑定关系的创建有以下两种:- 当协议中定义了设备注册功能时, 由 数据处理脚本 函数在接收到设备注册数据包时, 通过调用 client 中的 register 向驱动注册设备实现设备与连接折绑定.
- 当协议中未定义设备注册功能时, 驱动会自动记录每个设备是由哪个连接上报实时数据的(设备每次上传实时数据时都会自动更新), 当驱动下发指令时, 会自动根据该信息向对应的连接发送指令数据.
注: 如果通过 **register** 函数注册了设备时, 会忽略根据实时数据建立的绑定关系. 如果协议中未定义设备注册功能并且设备未上报过实时数据时, 无法通过实时数据建立绑定关系, 此时无法向该设备发送数据
-