1.背景

Fox-Edge在前期方案中,是采用静态解码器方案,也就是基于JAVA的JAR包反射技术,编写解码器,这样的话就能够获得更好编码/解码的性能。

但是,这种方案在实践中,除了性能,其他体验并不是很好。

JAR解码器 的主要缺点:

1、这是一个静态方案,而不是一个动态方案,每次修改代码都要重启Device服务,没有动态的即时修改即时效果可见的特性。

2、这不是一个跨语言的方案,这导致除了JAVA开发者开发的Device服务,比如GO、C++语言开发的Device服务,JAR包都是不可用的。

所以,后面决定采用 JS解码器 作为动态解码器的实现方案。

1.1 ECMAScript

ECMAScript 是由ECMA(欧洲计算机制造商协会)通过ECMA-262标准规范的一种脚本程序设计语言,其目标是实现跨平台编程语言的标准化。 ‌

该语言标准化了以JavaScript为代表的脚本语言家族,具有结构化、动态、函数式和原型编程等特性。

从而使各主流开发语言,都能根据该标准实现一个JavaScript执行器,从而使之成为跨软硬件平台的标准化语言。

比如JAVA、GO、NodeJS,都支持在进程内部开启 JavaScript引擎 ,将符合ECMAScript标准的JavaScript,装载到进程中运行。

在运行的过程之中,JavaScript被嵌入到主进程之中,主进程能够跟JavaScript进行数据交换和函数调用。

2.方案

JavaScript实现的代码,是一个完整的脚本化程序,它可以在各大主流语言的集成化开发环境中被编写、调试和运行。这边推荐使用JAVA的 IDEA 这个集成化工具。

Fox-Edge为了让JS代码更容易编写、维护和调试,将一个JS程序,分拆成一个主程序和多个库的软件代码的项目管理方式。

Fox-Edge的 device-service 服务启动的时候,会为各设备类型创建一个JavaScript引擎,然后将开发者的JS代码,都装载到JavaScript引擎之中。

JavaScript引擎会自行分析JavaScript代码的语法,组织成一个完整的JS工程代码,然后运行开发者的JS代码。

device-service服务的主进程,在接收到上面的请求和设备返回的数据时,会将设备的参数以 fox_edge_param 传递给JavaScript引擎, 将设备返回的报文以 fox_edge_data 传递给JavaScript引擎,然后会调用JavaScript的 encode()decode() 函数进行报文的编码和解码。

通过上面的过程,从而实现了 动态解码器

2.1 前期准备

可以提前准备一个MODBUS设备作为测试设备。

如果没有真实的MODBUS设备,也可以使用MODBUS模拟器 Modbus Slave 模拟一个设备进行测试。同时安装一个虚拟串口工具 Virtual Serial Port Driver , 用于串口通道服务或者串口调试工具,可以以串口方式去连接MODBUS模拟设备。

3.步骤

基本步骤:创建动态解码器》创建设备对象》添加设备操作》查看设备数值

3.1 创建动态解码器

基本步骤:新增解码器》创建操作》编辑JS代码

3.1.1 新增解码器

新增一个解码器,基本步骤:本地组件(菜单)》动态解码(菜单)》新增(按钮)

在新增对话框中,可以填入设备厂商、设备型号信息,则创建了一个空的解码器。

那么,就后面就可以通过该设备型号信息,创建对应的设备了

3.1.2 创建操作

基本步骤:本地组件(菜单)》动态解码(菜单)》选择解码器(表单)》下一步(按钮)》新增(按钮)

在新增对话框中,可以填入操作名称、业务类型、操作模式、数据类型等信息。

3.1.2.1 操作名称

一个设备允许建立多个操作,它代表了一个对设备对的操作方法或者代码库,名称在设备内保持唯一性。

3.1.2.2 业务类型

在Fox-Edge中,支持设备级别的解码器和通道级别的解码器,那么对应的,就可以创建 设备类型 或者 通道类型 的解码器

3.1.2.3 操作模式

在Fox-Edge中,操作模式定义了这个操作的行为特征。

设备类型,它支持问答操作、上报操作、发布操作、库函数。

3.1.2.4 操作模式

在Fox-Edge中,操作模式定义了这个操作的行为特征。

设备类型,它支持问答操作、上报操作、发布操作、库函数。

3.1.2.5 数据类型

在Fox-Edge中,数据类型定义了这个操作的返回的数据格式,而不同的数据类型,又会被保存在不同的地方。

3.1.3 编辑JS代码

基本步骤:本地组件(菜单)》动态解码(菜单)》选择解码器(表单)》下一步(按钮)》选择操作(表单)》下一步(按钮)

在页面中,会展示操作的JavaScript代码,可以将其复制出来,复制到IDEA中去进行调试,调试完成之后,再复制回代码编辑框,保存起来。

在Fox-Edge中,操作根据操作模式,自动分为编码函数、解码函数、库函数。

/**
 * 编码器的入口函数
 * 全局参数:
 *     fox_edge_param:json string格式的设备参数的合并对象
 * 返回值:
 *   提供给通道的发送数据。根据不同的通道服务,它可能是HEX结构的文本,也可能是JSON结构的对象,请自行根据选定的通道服务进行确认
 */
function encode() {
    var param = JSON.parse(fox_edge_param);
    var userParam = buildUserParam(param.devAddr)
    return encodeReadHoldingRegisterRequest(userParam);
}

/**
 * 编码器的入口函数
 * 全局参数:
 *     fox_edge_data:json string格式 或者 hex string格式的接收数据
 *     fox_edge_param:json string格式的设备参数的合并对象
 * 返回值:
 *   提供给通道的发送数据。根据不同的通道服务,它可能是HEX结构的文本,也可能是JSON结构的对象,请自行根据选定的通道服务进行确认
 */
function decode() {
    var param = JSON.parse(fox_edge_param);
    var userParam = buildUserParam(param.devAddr)
    var result = decodeReadHoldingRegisterRespond(fox_edge_data, userParam);
    return JSON.stringify(result);
}

/**
 * 数组转换为hex
 *
 * @param uint8Array
 * @returns {string}
 */
function arrayToHex(uint8Array) {
    var hex = "";
    for (var i = 0; i < uint8Array.length; i++) {
        var ch = uint8Array[i].toString(16);
        hex += padStart(ch, 2, '0').toUpperCase();
    }

    return hex;
}

/**
 * hex转数组
 * @param hex
 * @returns {Uint8Array}
 */
function hexToArray(hex) {
    var hex = hex.replace(/\s+/g, "").toUpperCase();
    var uint8Array = new Uint8Array(hex.length / 2);
    for (var i = 0; i < uint8Array.length; i++) {
        uint8Array[i] = parseInt(hex[2 * i] + hex[2 * i + 1], 16);
    }

    return uint8Array;
}

3.2 创建设备对象

基本步骤:创建通道》创建设备

3.2.1 创建通道

基本步骤:通道管理(菜单)》通道列表(菜单)》新增(按钮)

创建一个跟你的设备对应通道方式的通道,用来跟设备建立通信连接。

例如:一个RS485的MODBUS设备,你可以创建一个serial类型的通道,并配置好通道参数。

{
     "baudRate": 9600,
     "databits": 8,
     "parity": "N",
     "serialName": "ttyUSB0",
     "stopbits": 1
}

如果通信参数正确的话,那么Fox-Edge就可以跟你的设备进行报文的通信了。你如果知道设备的发送命令报文的话,你可以进行跟设备进行通信测试,检查连通性。

基本步骤:任务管理(菜单)》通道操作任务(菜单)》新增(按钮)》点击记录(表单)》发送(按钮)

那么,你可以看到你跟设备的发送和应答报文。

更具体的内容,可以看下面一段的**【添加操作任务】**内容

3.2.2 创建设备

基本步骤:设备管理(菜单)》设备列表(菜单)》新增(按钮)

当你在前面创建过一个设备解码器后,那么在创建设备对话框中,就会出现你解码器定义的设备型号。

然后,你可以创建这个型号的设备对象,并绑定该上面建立的通道。

如果你的JS解码器,指明了要给它传递一些工作参数,比如MODBUS设备要给它传递一个设备地址、MODBUS的工作模式,那么你要在配置参数中,填入解码器要求的JSON参数。

3.3 添加操作任务

目的:验证Fox-Edge能够跟设备进行正常通信。

基本步骤:创建通道操作任务》创建设备操作任务》创建设备监控任务

3.3.1 创建通道操作任务

基本步骤:任务管理(菜单)》通道操作任务(菜单)》新增(按钮)

创建一个通道操作任务,用来测试Fox-Edge跟设备之间通信连接,是否通信正常。

然后点击该记录后,再点击 发送 按钮,那么你会看到向设备请求报文,设备应答了对应的内容。

3.3.2 创建设备操作任务

目的:验证Fox-Edge的解码器能够对设备进行正常操作。

基本步骤:任务管理(菜单)》设备操作任务(菜单)》新增(按钮)

创建一个设备操作任务,用来测试Fox-Edge对设备的操作,是否工作正常。

然后点击该记录后,再点击 发送 按钮,那么你会看到在使用JS解码器进行报文编码后,向设备请求报文, 当设备应答了对应的内容,解码器会进行报文的解码,从而得到具体的设备数据。

[
     {
          "uuid": "4478d696-074d-48f9-985e-d5464fb96630",
          "operateMode": "exchange",
          "operateName": "读取数据",
          "manufacturer": "武汉辰云科技有限公司",
          "deviceType": "YGC-BYX-M",
          "deviceName": "百叶箱温湿压传感器",
          "param": {},
          "timeout": 2000,
          "record": true,
          "data": {
               "commStatus": {
                    "commFailedCount": 0,
                    "commFailedTime": 0,
                    "commSuccessTime": 1760952052275
               },
               "value": {
                    "operateName": "读取数据",
                    "status": {
                         "humidity": {
                              "time": 1760952052275,
                              "value": 57.900000000000006
                         },
                         "temperature": {
                              "time": 1760952052275,
                              "value": 26.1
                         }
                    }
               }
          },
          "msg": "",
          "code": 200
     }
]

3.3.3 创建设备监控任务

目的:为Fox-Edge编排一个自动化执行的任务,方便进行数据的采集。

基本步骤:任务管理(菜单)》设备监控任务(菜单)》新增(按钮)》绑定(按钮)

创建一个设备监控任务,用来进行现场设备的周期性数据采集。

[
     {
          "operateMode": "exchange",
          "operateName": "读取数据",
          "param": {},
          "timeout": 2000
     }
]

然后点击该记录后,再点击 绑定 按钮,那么你就可以选择将该任务应用在哪些设备上。 那么 controller 就会根据这些配置,进行设备数据的自动采集

3.4 查看设备数值

基本步骤:设备管理(菜单)》设备数值(菜单)》搜索(按钮)

如果设备通信正常的话,那么设备数值页面,可以查询到该设备的当前采样数值,并且不断从设备侧采集,并数据刷新。

4 云端发布

可以在云端仓库 中创建一个同名的设备解码器项目, 用于从Fox-Edge提交动态解码器,从而在其他项目中被使用。

4.1 新增解码器

基本步骤:本地组件(菜单)》动态解码(菜单)》同步(按钮)》上传(按钮)

那么,在本地同名解码器中,就可以通过先同步云端信息,再上传发布解码器了