Fox-Edge在前期方案中,是采用静态解码器方案,也就是基于JAVA的JAR包反射技术,编写解码器,这样的话就能够获得更好编码/解码的性能。
但是,这种方案在实践中,除了性能,其他体验并不是很好。
JAR解码器 的主要缺点:
1、这是一个静态方案,而不是一个动态方案,每次修改代码都要重启Device服务,没有动态的即时修改即时效果可见的特性。
2、这不是一个跨语言的方案,这导致除了JAVA开发者开发的Device服务,比如GO、C++语言开发的Device服务,JAR包都是不可用的。
所以,后面决定采用 JS解码器 作为动态解码器的实现方案。
ECMAScript 是由ECMA(欧洲计算机制造商协会)通过ECMA-262标准规范的一种脚本程序设计语言,其目标是实现跨平台编程语言的标准化。
该语言标准化了以JavaScript为代表的脚本语言家族,具有结构化、动态、函数式和原型编程等特性。
从而使各主流开发语言,都能根据该标准实现一个JavaScript执行器,从而使之成为跨软硬件平台的标准化语言。
比如JAVA、GO、NodeJS,都支持在进程内部开启 JavaScript引擎 ,将符合ECMAScript标准的JavaScript,装载到进程中运行。
在运行的过程之中,JavaScript被嵌入到主进程之中,主进程能够跟JavaScript进行数据交换和函数调用。
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() 函数进行报文的编码和解码。
通过上面的过程,从而实现了 动态解码器
可以提前准备一个MODBUS设备作为测试设备。
如果没有真实的MODBUS设备,也可以使用MODBUS模拟器 Modbus Slave 模拟一个设备进行测试。同时安装一个虚拟串口工具 Virtual Serial Port Driver , 用于串口通道服务或者串口调试工具,可以以串口方式去连接MODBUS模拟设备。
基本步骤:创建动态解码器》创建设备对象》添加设备操作》查看设备数值
基本步骤:新增解码器》创建操作》编辑JS代码
新增一个解码器,基本步骤:本地组件(菜单)》动态解码(菜单)》新增(按钮)
在新增对话框中,可以填入设备厂商、设备型号信息,则创建了一个空的解码器。
那么,就后面就可以通过该设备型号信息,创建对应的设备了
基本步骤:本地组件(菜单)》动态解码(菜单)》选择解码器(表单)》下一步(按钮)》新增(按钮)
在新增对话框中,可以填入操作名称、业务类型、操作模式、数据类型等信息。
一个设备允许建立多个操作,它代表了一个对设备对的操作方法或者代码库,名称在设备内保持唯一性。
在Fox-Edge中,支持设备级别的解码器和通道级别的解码器,那么对应的,就可以创建 设备类型 或者 通道类型 的解码器
在Fox-Edge中,操作模式定义了这个操作的行为特征。
设备类型,它支持问答操作、上报操作、发布操作、库函数。
问答操作 :指的是一问一答,也就是生成一段发送报文,发送给设备,等待设备的报文返回,然后对返回报文进行解码。这是大多数设备支持的工作模式。
上报操作 :指的是对设备不断上报的数据进行解码,也就是设备会定期的上报数据报文,然后对收到的设备上报报文进行解码。比如在LORA组网场景下, LORA设备通常不接收上面对它的操作命令,只会定期上报数据给上面的系统。
发布操作 :指的是对设备进行单向的下行命令进行编码,也就是设备只接收命令,但是并不进行应答。比如某些基于HTTP、TCP的子系统,它们有些操作是 只要通过HTTP、TCP连接后,发送一个报文过去,则执行你的操作请求,它们并不会在执行完成之后进行应答。
库函数 :可以将一个复杂的解码器,分成一个入口函数,多个库函数的组织方式,从而提高代码的可维护性。
在Fox-Edge中,操作模式定义了这个操作的行为特征。
设备类型,它支持问答操作、上报操作、发布操作、库函数。
问答操作 :指的是一问一答,也就是生成一段发送报文,发送给设备,等待设备的报文返回,然后对返回报文进行解码。这是大多数设备支持的工作模式。
上报操作 :指的是对设备不断上报的数据进行解码,也就是设备会定期的上报数据报文,然后对收到的设备上报报文进行解码。比如在LORA组网场景下, LORA设备通常不接收上面对它的操作命令,只会定期上报数据给上面的系统。
发布操作 :指的是对设备进行单向的下行命令进行编码,也就是设备只接收命令,但是并不进行应答。比如某些基于HTTP、TCP的子系统,它们有些操作是 只要通过HTTP、TCP连接后,发送一个报文过去,则执行你的操作请求,它们并不会在执行完成之后进行应答。
库函数 :可以将一个复杂的解码器,分成一个入口函数,多个库函数的组织方式,从而提高代码的可维护性。
报文分拆 :这是通道级别的操作,TCP、RS232是数据流的通信方式,但是有些设备在上面传输数据报,那么就涉及到报文的分拆操作,也就是从一段长报文中, 分析是否包含符合本设备协议定义的一段数据报文,并将其摘出来,作为一个数据报,上报给device-service服务,进行进一步数据解析处理。
身份识别 :这是通道级别的操作,某些设备它们是从下面主动发起接入到Fox-Edge的,这些设备会携带 身份ID 以及其他信息,那么就可以在接收到这些信息后, 自动创建一个通道或者设备,从而实现设备的自动发现和创建能力。比如,LORA网络中的设备,它们通常会以JSON格式主动上报自己的数据,这个数据就包括LORA设备的ID标识。
在Fox-Edge中,数据类型定义了这个操作的返回的数据格式,而不同的数据类型,又会被保存在不同的地方。
设备状态 :指的是设备的当前状态,比如温度值、湿度值、电压值,这是大多数设备返回的数据形态。它会被保存在redis中,可以在 设备管理(菜单)》设备数值(菜单) 页面看到这些数据。
设备记录 :指的是设备的发生了某个事件,比如设备告警、门禁的刷卡进门、摄像头抓拍等事件动作。它会被保存在数据库tb_device_record中,可以在 记录管理(菜单)》设备记录(菜单) 页面看到这些数据。
时序记录 :指的是设备的产生了一组连续的时序数据,比如位移计设备测量了十秒内,每100毫秒为间隔,总共100个位移数据。它会被保存在数据库tb_sequence_xxxxxx中,可以在记录管理(菜单)》时序记录(菜单) 页面看到这些数据。
基本步骤:本地组件(菜单)》动态解码(菜单)》选择解码器(表单)》下一步(按钮)》选择操作(表单)》下一步(按钮)
在页面中,会展示操作的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;
}
基本步骤:创建通道》创建设备
基本步骤:通道管理(菜单)》通道列表(菜单)》新增(按钮)
创建一个跟你的设备对应通道方式的通道,用来跟设备建立通信连接。
例如:一个RS485的MODBUS设备,你可以创建一个serial类型的通道,并配置好通道参数。
{
"baudRate": 9600,
"databits": 8,
"parity": "N",
"serialName": "ttyUSB0",
"stopbits": 1
}
如果通信参数正确的话,那么Fox-Edge就可以跟你的设备进行报文的通信了。你如果知道设备的发送命令报文的话,你可以进行跟设备进行通信测试,检查连通性。
基本步骤:任务管理(菜单)》通道操作任务(菜单)》新增(按钮)》点击记录(表单)》发送(按钮)
那么,你可以看到你跟设备的发送和应答报文。
更具体的内容,可以看下面一段的**【添加操作任务】**内容
基本步骤:设备管理(菜单)》设备列表(菜单)》新增(按钮)
当你在前面创建过一个设备解码器后,那么在创建设备对话框中,就会出现你解码器定义的设备型号。
然后,你可以创建这个型号的设备对象,并绑定该上面建立的通道。
如果你的JS解码器,指明了要给它传递一些工作参数,比如MODBUS设备要给它传递一个设备地址、MODBUS的工作模式,那么你要在配置参数中,填入解码器要求的JSON参数。
目的:验证Fox-Edge能够跟设备进行正常通信。
基本步骤:创建通道操作任务》创建设备操作任务》创建设备监控任务
基本步骤:任务管理(菜单)》通道操作任务(菜单)》新增(按钮)
创建一个通道操作任务,用来测试Fox-Edge跟设备之间通信连接,是否通信正常。
通道类型 :在你启动某个通道通道服务后,那么它会出现你这个通道服务支持的通道类型。比如,你启动serial通道服务,那么这边就会出现一个serial类型。
通道名称 :在前面创建通道阶段,创建的通道
发送模式 :如何发送数据给设备,包括 exchange 和 publish 两种模式。exchange指的是一问一答的主动半双工方式,publish指的是只发送, 不需要回答的方式。注意:这个模式是要通道服务来支持的。
通信超时 :在exchange模式下,发送报文后,等待设备报文的返回,可以最大等待的时间,如果设备在规定的时间内没有返回,那么就认定为设备通信超时了。
参数类型 :你发送的报文,会有三种报文格式:sendTxt 是HEX格式的报文,sendMap 是JSON格式中的MAP格式报文, sendList 是JSON格式中的List格式报文。具体是哪种格式,这是由通道服务所支持的类型来决定的。
模板参数 :你准备向设备发送的具体报文。注意,这个报文是设备可识别并应答的报文。
然后点击该记录后,再点击 发送 按钮,那么你会看到向设备请求报文,设备应答了对应的内容。
目的:验证Fox-Edge的解码器能够对设备进行正常操作。
基本步骤:任务管理(菜单)》设备操作任务(菜单)》新增(按钮)
创建一个设备操作任务,用来测试Fox-Edge对设备的操作,是否工作正常。
设备信息 :包括选择 设备厂商 、 设备类型 、 设备名称 ,指明要进行操作验证的某个设备。
操作名称 :该设备支持的操作,也就是上面写解码器时,所定义的该设备型号具有哪些操作。
操作模式 :如何发送数据给设备,包括 exchange 和 publish 两种模式。exchange指的是一问一答的主动半双工方式,publish指的是只发送, 不需要回答的方式。注意:这个模式是要通道服务来支持的。
模板参数 :对设备进行操作的时候,开发人员编写的解码器,会要求你给他传递一些设备的可配置参数。比如,MODBUS设备的解码器会要求你传递读取多少个寄存器。 它的参数格式是JSON格式,具体格式,是由该设备型号的JS解码器规定,如何填写,开发人员通常会在他编写的解码器操作写有备注信息,或者是制作有默认的设备模板, 告诉你格式改如何填写。
设备模板 :包括选择 可用子集 、 可用模板 ,用于给出参数填写的范例。开发人员在编写完成自己的解码器之后, 为了方便告知使用者该如何填写命令参数,可以在 设备模板 中,为该款解码器填写通道参数、设备参数、操作参数的默认格式。那么会自动出现设备参数,选择填入。
通信超时 :设备响应的最大超时时间。
然后点击该记录后,再点击 发送 按钮,那么你会看到在使用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
}
]
目的:为Fox-Edge编排一个自动化执行的任务,方便进行数据的采集。
基本步骤:任务管理(菜单)》设备监控任务(菜单)》新增(按钮)》绑定(按钮)
创建一个设备监控任务,用来进行现场设备的周期性数据采集。
设备信息 :包括选择 设备厂商 、 设备类型 ,指明这是为某个类型的设备进行的编排任务。
采样周期 :该任务以多少时间的间隔,进行一次采样任务的执行。
模板参数 :将前面测试通过后的一个个 设备操作任务 ,将它们的JSON MAP参数复制过来,组成JSON LIST参数,构成一组动作列表,对设备进行数据的采集。 参数复制的时候,要包括: operateMode 、 operateName 、 param 、 timeout ,这四个参数
[
{
"operateMode": "exchange",
"operateName": "读取数据",
"param": {},
"timeout": 2000
}
]
然后点击该记录后,再点击 绑定 按钮,那么你就可以选择将该任务应用在哪些设备上。 那么 controller 就会根据这些配置,进行设备数据的自动采集
基本步骤:设备管理(菜单)》设备数值(菜单)》搜索(按钮)
如果设备通信正常的话,那么设备数值页面,可以查询到该设备的当前采样数值,并且不断从设备侧采集,并数据刷新。
可以在云端仓库 中创建一个同名的设备解码器项目, 用于从Fox-Edge提交动态解码器,从而在其他项目中被使用。
基本步骤:本地组件(菜单)》动态解码(菜单)》同步(按钮)》上传(按钮)
那么,在本地同名解码器中,就可以通过先同步云端信息,再上传发布解码器了