规则脚本
大约 6 分钟
1、脚本语言
提示
规则脚本采用Groovy编写,是一种基于JVM(Java虚拟机)的敏捷开发语言,Groovy代码能够与Java代码很好的结合,也能用于扩展现有代码。
Groovy的语法与 Java 语言的语法很相似,完成同样的任务所需的代码比 Java 代码更少。可以将它想像成 Java 语言的一种更加简单、表达能力更强的变体,基本上可以直接使用Java代码编写脚本。
2、新建规则脚本
规则脚本列表
编辑规则脚本
配置说明:
- 脚本事件:设备上报(已支持)、服务下发(已支持)、设备上线、设备离线
- 脚本动作:消息重发(已支持)、消息通知、Http推送、mqtt桥接、数据库存储
- 所属产品:规则脚本跟产品绑定,只会影响产品下面的设备
- 脚本顺序:产品下面有多个脚本,按照顺序执行
3、规则脚本基础示例
重要
如果设备的Mqtt消息格式是固定的,可以通过规则引擎进行转发,适配到平台,系统目前版本只支持Mqtt传输协议的主题和内容转发
- 系统自带netty-mqtt: 支持主题和内容转发
- 使用emqx中间件: 支持内容转发,主题可以通过emqx自带的规则引擎转发,emqx规则引擎介绍
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.util.NumberUtil;
// 1. 获取主题/消息内容/设备编号/协议编码
String topic = msgContext.getTopic();
String payload = msgContext.getPayload();
String serialNumber = msgContext.getSerialNumber();
String protocolCode = msgContext.getProtocolCode();
// 2. 数据转换(自己处理)
msgContext.logger.info("数据转换处理")
String NewTopic = topic;
String NewPayload = payload;
// 3. 返回新的数据
msgContext.setTopic(NewTopic);
msgContext.setPayload(NewPayload);
提示
- 默认仅使用hutool的Json处理和数字工具类库,hutool其他类库或者系统相关类库,需要后端开放一下;
- 默认禁止使用For/While循环和IO操作等,根据情况可以后端开放;
- 通过msgContext获取和设置主题和消息内容;
- 主题和消息内容如何转换需要自己编写。
规则脚本通过上下文 MsgContext
存取数据。脚本中可以通过 msgContext
获取值和重新设置新的值,系统定义的上下文如下:
public class MsgContext {
/** 消息主题 */
private String topic;
/** 消息内容 */
private String payload;
/** 设备编号 */
private String serialNumber;
/** 产品ID */
private Long productId;
/** 协议编码 */
private String protocolCode;
}
4. 设备上报示例
我们创建一个产品,产品选择JSON协议
按照平台处理上报数据的系统主题和系统数据格式分别是:
Topic: /96/D1ELV3A5TOJS/property/post
[
{
"id": "temperature",
"value": "26.45"
},
{
"id": "humidity",
"value": "65.8"
}
]
实际设备上报的数据格式和主题分别是:
Topic: D1ELV3A5TOJS/post
{
"temperature": 26.5,
"humidity": 65.8
}
此时,我们使用脚本转换主题和数据格式,我们新建一个脚本
脚本内容如下:
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.util.NumberUtil;
//系统主题
String sysTopic = '';
//系统数据格式
String sysPayload = '';
// 1. 获取主题和内容,topic S&D1PGLPG58K66/post
String name = msgContext.getTopic();
Long productId = msgContext.getProductId();
String serialNumber = msgContext.getSerialNumber();
String protocolCode = msgContext.getProtocolCode();
String payload = msgContext.getPayload();
msgContext.logger.info("产品id/协议编号:" + productId + " / " + protocolCode);
// 2. 转换为系统主题 /96/D1ELV3A5TOJS/property/post
sysTopic = "/" + productId + "/" + serialNumber + "/property/post"
if("JSON".equals(protocolCode)){
// 3. 内容格式转换
JSONArray newArray = new JSONArray();
JSONObject jsonObject = JSONUtil.parseObj(payload);
jsonObject.keySet().forEach(key -> {
JSONObject newObject =new JSONObject();
newObject.put("id" , key);
newObject.put("value" , jsonObject.getStr(key));
newArray.add(newObject);
});
sysPayload = newArray.toString();
}else{
//其他协议处理
}
// 4.打印
msgContext.logger.info("新主题:" + sysTopic);
msgContext.logger.info("新内容:" + sysPayload);
// 5. 返回新的数据(必要)
msgContext.setTopic(sysTopic)
msgContext.setPayload(sysPayload);
脚本内容基本比较容易理解。我们编辑好脚本后,进行验证。运行一下看看效果。连接设备编号为:S&D1PGLPG58K66 的设备,按照如下格式发送:
我们看看脚本执行后的在控制台打印的结果:
16:08:55.066 [MQTT-BROKER-6-5] INFO c.y.l.c.FlowExecutor - [info,186] - [68bc37d0dffa41a8a25b1d8c1a63a8a5]:requestId has generated
16:08:55.066 [MQTT-BROKER-6-5] INFO c.y.l.c.FlowExecutor - [info,193] - [68bc37d0dffa41a8a25b1d8c1a63a8a5]:slot[10] offered
16:08:55.066 [MQTT-BROKER-6-5] INFO c.y.l.f.element.Node - [info,193] - [68bc37d0dffa41a8a25b1d8c1a63a8a5]:[O]start component[D1751532166174609408(消息转发)] execution
----------------------------------------------------------------------------------------
产品id/协议编号:41 / JSON
新主题:/41/D1ELV3A5TOJS/property/post
新内容:[{"id":"temperature","value":"26.5"},{"id":"humidity","value":"65.8"}]
-----------------------------------------------------------------------------------------
16:08:55.067 [MQTT-BROKER-6-5] INFO c.y.l.c.ScriptCommonComponent - [info,200] - [68bc37d0dffa41a8a25b1d8c1a63a8a5]:component[D1751532166174609408(消息转发)] finished in 0 milliseconds
16:08:55.067 [MQTT-BROKER-6-5] INFO c.y.l.slot.Slot - [info,200] - [68bc37d0dffa41a8a25b1d8c1a63a8a5]:CHAIN_NAME[dataChain]
D1751532166174609408[消息转发]<0>
可以看到topic和数据格式已经转换为系统主题和格式
5. 服务下发转换示例
假设实际设备服务下发的主题和数据格式分别是:
Topic: D1PGLPG58KZ2/set
{
"report_monitor": "4"
}
平台系统主题和数据格式:
Topic: /96/D1PGLPG58K66/property/post
[
{
"id": "temperature",
"value": "26.45"
},
{
"id": "humidity",
"value": "65.8"
}
]
新增脚本,定义如下:
我们看看脚本的定义内容:
1.将系统主题转为真实设备需要的主题
2.将系统数据格式转为真实设备需要的主题(注意:主题转换时 设备编号必须带上且长度大于9位,如果不带设备编号,需要修改后端代码)
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.util.NumberUtil;
//系统主题
String tranTopic = '';
//系统数据格式
String tranPayload = '';
// 1. 获取主题和内容
String topic = msgContext.getTopic();
String payload = msgContext.getPayload();
Long productId = msgContext.getProductId();
String serialNumber = msgContext.getSerialNumber();
String protocolCode = msgContext.getProtocolCode();
// 2. topic转换 将/60/DEVICE555/function/get 系统主题 转为 DEVICE555/set
tranTopic = serialNumber+ "/set";
if("JSON".equals(protocolCode)){
// 3. 转发的数据 {"temperature":26.5,"humidity":65.8}
JSONArray jsonArray = JSONUtil.parseArray(payload);
JSONObject resultObj = new JSONObject();
jsonArray.forEach(obj -> {
JSONObject jsonObject = (JSONObject)obj;
resultObj.put(jsonObject.getStr("id"),jsonObject.getStr("value"));
});
tranPayload = JSONUtil.toJsonStr(resultObj);
}else{
//其他协议处理
}
// 4.打印
msgContext.logger.info("转发主题:" + tranTopic);
msgContext.logger.info("转发内容:" + tranPayload);
// 5. 返回新的数据(必要)
msgContext.setTopic(tranTopic);
msgContext.setPayload(tranPayload);
我们下发指令来测试一下转换情况,后端日志内容如下:
17:34:36.439 [functionInvokeTask2] INFO c.y.l.c.FlowExecutor - [info,186] - [6481bf113e15499aabe550189d16f4a5]:requestId has generated
17:34:36.440 [functionInvokeTask2] INFO c.y.l.c.FlowExecutor - [info,193] - [6481bf113e15499aabe550189d16f4a5]:slot[13] offered
17:34:36.440 [functionInvokeTask2] INFO c.y.l.f.element.Node - [info,193] - [6481bf113e15499aabe550189d16f4a5]:[O]start component[D1753673875549458432(平台下发转发)] execution
-------------------------------------------------
转发主题:D1PGLPG58KZ2/set
转发内容:{"report_monitor":"6"}
-----------------------------------------------
17:34:36.440 [functionInvokeTask2] INFO c.y.l.c.ScriptCommonComponent - [info,200] - [6481bf113e15499aabe550189d16f4a5]:component[D1753673875549458432(平台下发转发)] finished in 0 milliseconds
17:34:36.440 [functionInvokeTask2] INFO c.y.l.slot.Slot - [info,200] - [6481bf113e15499aabe550189d16f4a5]:CHAIN_NAME[dataChain]
客户端订阅接收内容如下:
至此,将系统主题和数据格式转换为设备所需主题和格式验证成功。