# DRL脚本编写教程
# 脚本详情
# import引入
引入依赖支持java.io 、java.lang 、java.util和com.hanclouds.hfc下的ProtocolApi、MessageContext的依赖,引入其他依赖校验不会通过。
import java.util.Map
import java.util.HashMap
import java.util.Date
import java.util.List
import java.util.Arrays
import java.util.ArrayList
import com.hanclouds.hfc.data.helper.ProtocolApi;
import com.hanclouds.hfc.common.beans.MessageContext
# 数据解析
该部分固定格式
rule "decode"
when
$m:MessageContext()
then
以下部分见API
ProtocolApi.newReadByteDataBuffer($m);
//获取messagecontex的字节报文
byte[] bytes=(byte[])($m.getProperty("context"));
//登陆报文 假设根据报文长度判断登陆或这心跳报文 11223344556677(模拟报文)
if(bytes.length==7){
Object data1 = ProtocolApi.read("BCD(2)",true,$m);
//设备唯一识别码 mac
String mac = ProtocolApi.read("BCD(2)",false,$m).toString();
Object data3 = ProtocolApi.read("I8",true,$m);
Object data4 = ProtocolApi.read("I8",true,$m);
Object data5 = ProtocolApi.read("I8",true,$m);
ProtocolApi.setTestLog($m,"mac"+mac);
ProtocolApi.login($m,mac,600);
ProtocolApi.addDownTask((byte[])($m.getProperty("context")),$m,-1000,0);
//定时任务下行任务后,上行的数据报文 1122334455667711223344556677(模拟报文)
}else if(bytes.length==14){
// 数据设备的地址sn
String sn = ProtocolApi.read("I8",true,$m).toString();
Object afn = ProtocolApi.read("I8",true,$m);
Object length = ProtocolApi.read("I8",true,$m);
String data1 = ProtocolApi.read("I16",true,$m).toString();
String data2 = ProtocolApi.read("I16",true,$m).toString();
String data3 = ProtocolApi.read("C(7)",true,$m).toString();
ProtocolApi.setTestLog($m,"data1"+data1);
ProtocolApi.setTestLog($m,"data2"+data2);
List<Map<String,String> >dataMap = new ArrayList<>();
Map<String,String> map = new HashMap<>();
map.put("equipmentNo",sn);
map.put("dataItemCode","1");
map.put("dataTime","1");
map.put("dataValue",data1);
dataMap.add(map);
map = new HashMap<>();
map.put("equipmentNo",sn);
map.put("dataItemCode","1");
map.put("dataTime","1");
map.put("dataValue",data2);
dataMap.add(map);
map = new HashMap<>();
map.put("equipmentNo",sn);
map.put("dataItemCode","1");
map.put("dataTime","1");
map.put("dataValue",data3);
dataMap.add(map);
ProtocolApi.userData("1",$m,"data",dataMap);
//控制指令下行,后上行的控制指令回复报文 11223344556677112233(模拟报文)
}else if(bytes.length==11){
String sn = ProtocolApi.read("I8",true,$m).toString();
Object afn = ProtocolApi.read("I8",true,$m);
Object length = ProtocolApi.read("I8",true,$m);
String data1 = ProtocolApi.read("I16",true,$m).toString();
String data2 = ProtocolApi.read("I16",true,$m).toString();
String data3 = ProtocolApi.read("F",true,$m).toString();
List<Map<String,String> >dataMap = new ArrayList<>();
Map<String,String> map = new HashMap<>();
map.put("equipmentNo",sn);
map.put("dataItemCode","1");
map.put("dataTime","1");
map.put("dataValue",data1);
dataMap.add(map);
map = new HashMap<>();
map.put("equipmentNo",sn);
map.put("dataItemCode","1");
map.put("dataTime","1");
map.put("dataValue",data2);
dataMap.add(map);
map = new HashMap<>();
map.put("equipmentNo",sn);
map.put("dataItemCode","1");
map.put("dataTime","1");
map.put("dataValue",data3);
dataMap.add(map);
ProtocolApi.returnDataCmdResult("1",$m,dataMap);
}
end
# 定时任务
一般情况下,定时任务和数据组装使用
固定部分:其中时间间隔配置和quartz格式一致
rule "timer"
timer (cron: */20 * * * * ? )
when
$m:MessageContext()
then
以下部分见API
ProtocolApi.task($m);
end
# 数据组装
固定部分
rule "encode"
when
$m:MessageContext()
then
以下部分见API
//6800010002(模拟报文)
ProtocolApi.newWriteByteDataBuffer($m);
byte[] message = new byte[0];
ProtocolApi.setTestLog($m,"timer test!");
message = ProtocolApi.write("I8",true,104,$m);
message = ProtocolApi.write("I16",true,1,$m);
message = ProtocolApi.write("I16",true,2,$m);
ProtocolApi.addDownTask(message,$m,-1000,0);
end
# 接口数据下发
接口数据下发是通过点击命令下发,下发报文
固定部分
rule "interfaceData"
when
$m:MessageContext()
then
以下部分见API
//6800030004(模拟报文)
byte[] message = new byte[0];
ProtocolApi.newWriteByteDataBuffer($m);
message = ProtocolApi.write("I8",true,104,$m);
message = ProtocolApi.write("I16",true,3,$m);
message = ProtocolApi.write("I16",true,4,$m);
ProtocolApi.addDownTask(message,$m,-1000,0);
end
# API
# 登录
ProtocolApi login(MessageContext content,String mac,int timeout)
* @param content MessageContext对象
* @param mac 设备sn地址
* @param timeout 设置登陆失效时间,通常设置600秒
* @return 无
# 数据解析
ProtocolApi read(String format, Boolean inBigEndian,MessageContext content)
* @param format 点击下方[数据类型]
* @param inBigEndian 数据值大小端,true大端,false小端
* @param content MessageContext对象
* @return Object Object
# 数据组装
ProtocolApi write(String format,Boolean inBigEndian,Object data,MessageContext content)
* @param format 点击下方[数据格式]
* @param inBigEndian 数据值大小端,true大端,false小端
* @param content MessageContext对象
* @return byte[]
# 下行报文
ProtocolApi send(byte[] message,MessageContext content)
* @param message 组装完成的字节数组
* @param content MessageContext对象
* @return 无
# 下行报文,设置延迟下发时间
ProtocolApi addDownTask(byte[] message,MessageContext context,int level,int delayTime)
* @param message 字节数组报文
* @param context MessageContext对象
* @param level 下发优先级(0,1,2,3,-1000)数字越小等级越高,-1000为直接回发,delayTime无效
* @param delayTime 延时时间(报文下发等待时间,超时未收到报文回复下发下一条报文,单位是毫秒值
* @return 无
# 数据推送
ProtocolApi userData(String deviceType,MessageContext content,String streamName,List<Map<String,String> >data)
* @param deviceType "01":通信设备;"02":测量设备;"03":两者兼具,可为null
* @param content MessageContext对象
* @param streamName 数据流名称,例如"xx/json","xx"为自定义命名,不能为汉字等非法字符
* @param data 数据格式为:
[{ "equipmentNo":xx,"dataItemCode":xx,"dataTime":xx,"dataValue":xx}]
* @return 无
# 返回应用调用结果
ProtocolApi returnDataCmdResult(String deviceType,MessageContext context,List<Map<String,String> >data)
使用接口下发功能时,使用该方法进行数据上传.
* @param deviceType "01":通信设备;"02":测量设备;"03":两者兼具,可为null
* @param context MessageContext对象
* @param data 数据格式为:
[{ "equipmentNo":xx,"dataItemCode":xx,"dataTime":xx,"dataValue":xx}]
* @return 无
# 调试日志打印
ProtocolApi setTestLog(MessageContext content, Object str)
* @param content MessageContext对象
* @param str 需要打印的内容
* @return 无
# 定时任务处理
ProtocolApi task(MessageContext content)
* @param content MessageContext对象
* @return 无
# 在读取数据时,往MessageContext里面设置一个数组对象
ProtocolApi newReadByteDataBuffer(MessageContext content)
* @param content MessageContext对象
* @return 无
# 在写取数据时,往MessageContext里面设置一个数组对象
ProtocolApi newWriteByteDataBuffer(MessageContext content)
* @param content MessageContext对象
* @return 无
# 数据格式
# 上行数据格式
{
"msgSrc": "01",
"msgType": "01",
"msgContent": [{
"equiId": null,
"sn": null,
"t": 1536917855086,
"type": "1"
"items": [{
"k": "10441026",
"v": "1111111111102#"
},
{
"k": "10441027",
"v": "55.07"
}]
}],
"resultCode": 0,
"resultMsg": "任务处理完成",
"taskId": "任务id",
"traceId": null
}
1、msgSrc为数据来源,"01"表示雾计算;非"01"就不解析
2、msgType为报文类型,"01"表示数据;"02"表示事件
3、msgContent为设备信息列表
-equiId:设备在瀚云平台上的key(deviceKey)
-sn:设备逻辑地址,也可能是采集器地址,依具体情况而定
-t:设备上报数据的时间戳,精确到秒
-type:设备类型,"01":通信设备;"02":测量设备;"03":两者兼具
-items:数据项列表,"K":数据项编码;"V":数据项编码对应的值,其数据类型可以灵活定义,但是所有数据项值的类型必须一致
4、resultCode为接口下发时上行报文处理结果状态码,数字0代表成功,非0代表失败,失败原因看resultMsg
5、resultMsg为失败原因
6、taskId为设备响应应用层下发的命令时,取下发时的任务id,没有则为空
7、traceId为日志信息id,可以为空
# 下行数据格式
备注:"bgn"、"end"参数间隔时间一般再30秒以内,"sn"是登陆时设备的sn地址
{
"bgn": 1538209894000,
"end": 1538219897000,
"interval": 0,
"items": [{
"k": "10441067",
"v": ""
}
],
"sn": "17",
"taskId": "LS1000954242",
"taskType": "",
"taskBlockFlag": "1",
"type": "03",
"msgType": ""
}
1、bgn/end都是时间戳,end>bgn,end-bgn为超时的毫秒数
2、interval为下发时间间隔,long类型,默认为0表示实时;非0表示具体的毫秒数
3、items为数据项列表,"k"表示数据项编码;"k"位数据项编码对应的值,其数据类型可以灵活定义
4、sn根据设备类型区分,既可以是采集器地址也可以是设备逻辑地址,类型为字符数组
5、taskId为下发任务id
6、taskType为下发任务类型,具体业务决定
7、taskBlockFlag为任务下发是否阻塞,默认为"0"阻塞;"1"表示不阻塞
8、type表示设备类型,"01":通信设备;"02":测量设备;"03":两者兼具
9、msgType为报文类型,下行报文可不填
# 数据类型
参数名称 | 名词解释 |
---|---|
I8 | 无符号位1个字节的整型 |
I16 | 无符号位2个字节的整型 |
I32 | 无符号位4个字节的整型 |
SI8 | 带符号位1个字节的整型 |
SI16 | 带符号位2个字节的整型 |
SI32 | 带符号位4个字节的整型 |
C(*) | 字符串,*表示数字1-N |
F | 浮点型 |
BCD(*) | BCD编码,,*表示数字1-N |
GBK(*) | GBK编码,*为4的倍数 |
BIGSIZE(*) | 任意长度,*表示数字1-N |
N(*) | BIT位,*表示数字1-N |
# 测试脚本数据格式
{
"rule_name": "decode",
"rule_params": {
"message": "11223344556677"
}
}
rule_name:脚本详情里面的 "decode"、"encode"、"timer"、"interfaceData"
rule_params:当rule_name为"decode"时,"message"需要配置成模拟报文解析,其他时候可不填