# 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"需要配置成模拟报文解析,其他时候可不填

# DRL脚本示例

点击查看 (opens new window)