王旭东
充电桩压测方案
海镕多联机空调485控制器方案说明
电能平台压测程序使用说明
中台软网关解析规则整理
星纵物联LoraWAN网关方案整理
国网376.1协议整理
云快充协议对接方案
科德4G水表离线问题排查
海镕3种空调平台与中台对接参数文档
电信AEP平台NB设备接入教程
牧原项目ARCM500蓝牙调试程序对接文档
中台-Expasion架构设计调整
中台-蓝牙调试小程序对接说明
ADW300-IOT报警新版参数设置(增加DO1和DO2联动)
迈格瑞能MPS微电网混合逆变器整理
微电网混合逆变器参数下发整理
云南交投充电桩协议对接方案
AAC系列空调控制器整理
云快充2.1协议对接方案(新增V2G协议)
本文档使用 MrDoc 发布
-
+
首页
中台软网关解析规则整理
### 解析规则 解析规则对应中台`ProtocolAdapterRule`类,维护在中台mongodb数据库`adp_ProtocolAdapterRule`表,目前以8890测试环境中台数据库维护的为准 #### 属性说明 ```js { "_id" : Long("665702490000006000"), //id唯一,不能重复 "productKey": "OTU1NzEzOTA5NjYyNDc4MzM2", //产品型号编码 "version": "0", //版本号,默认为0 "type": "DOWN", //规则类型 UP-上行/DOWN-下行 "format": "JSON", //报文格式 HEX-16进制、STRING-字符串、JSON、XML "assertRule": { //判断规则,用来获取关键字段如 method "prop": "command", //输出属性 "pipelines": [ //处理管道集合,所有管道按先后顺序执行,每个管道执行后的输出结果放入结果集 { "type": "COMPUTE", //管道类型,不同管道类型对于表达式的内容要求不一致 "param": "command", //输出参数名 "expression": "{'formula':'\"${method}\"'}" //表达式 }, { "type": "COMPUTE", "param": "command", "expression": "{'formula':\"'${payload}'&&'${payload.method}'?'${payload.method}':'${method}'\"}" } ] }, "transformRules": [ //转换规则集合,每一个转换规则对应一条命令的报文转换 { "code": "FORCECLOSE", //命令编码,与assertRule输出的command匹配即进到此转换规则中 "topic": "topic", //主题,上行解析表示报文发送给哪个主题,下行解析表示接收报文的主题 "prop": "output", //输出属性 "pipelines": [ { "type": "COMPUTE", //管道类型,不同管道类型对于表达式的内容要求不一致 "param": "addr", //输出参数名 "expression": "{'formula':\"'${payload.addr}'.split('_')[1]==undefined?'${payload.addr}'.split('_')[0]:'${payload.addr}'.split('_')[1]\"}" }, //表达式 { "type": "COMPUTE", "param": "port", "expression": "{'formula':\"'${payload.addr}'.split('_')[1]==undefined||'${payload.addr}'.split('_')[0]=='1'?'':'${payload.addr}'.split('_')[0]\"}" }, { "type": "COMPUTE", "param": "newAddr", "expression": "{'formula':\"'${port}'!=''?'${port}'+'_'+'${addr}':'${addr}'\"}" }, { "type": "COMPOSE", "param": "addr", "expression": "{'formula':'${addr}','outputFormat':'HEX','type':'EIGHT_INT'}" }, { "type": "COMPOSE", "param": "data", "expression": "{'formula':'${addr}050000FF00'}" }, { "type": "ALGORITHM", "param": "crc", "expression": "{'method':'CRC','param':'${data}'}" }, { "type": "COMPOSE", "param": "data", "expression": "{'formula':'${data}${crc}'}" }, { "type": "COMPOSE", "param": "output", //输出结果,下行指令规则必须要定义这个属性 //下行指令输出结果`expression`表达式必须满足下面的格式,`data`表示下发的报文, //`key`作为指令信息缓存在中台内存里的键名,用于接受到设备响应时根据键名获取指令信息 "expression": "{'formula':'{\"data\":\"${data}\",\"method\":\"${payload.method}\",\"key\":\"${sn}_${newAddr}_5\"}'}" } ] } ], "createTime": ISODate("2024-05-30T09:06:32.394Z"), //创建时间 "_class": "com.acrel.entity.adapter.ProtocolAdapterRule" //对应中台的类名 } ``` - 解析规则分为上行规则和下行规则,上行规则用来对设备上传的报文做解析处理,下行规则用来组成下发透传指令的报文,根据`type`属性区分,`UP`表示上行规则,`DOWN`表示下行规则 - 解析规则通过`productKey`属性区分设备所属的产品型号,对应中台`xch_Product`产品型号表的`productKey` - 新增解析规则时需要注意`_id`属性需要递增,不能重复 - 下行规则通过执行`assertRule`获取到`method`,通过和`transformRules`里每个转换规则里的`code`比对,找到相符的转换规则去处理,必须定义`param`为`output`的管道,作为下行规则最终的输出结果,`output`管道`expression`表达式的`formula`属性必须满足固定格式,包含`data`、`method`、`key`三个属性,`data`表示下发到设备的报文,`key`作为指令信息缓存在中台内存里的键名,用于收到设备响应时由设备号和报文命令字组成键名从缓存中获取对应指令信息,若`key`定义的键名和实际收到报文组成的键名不一致,指令会报失败超时 - 平台下发透传指令或者设备上传十六进制报文,进入解析规则处理时,会先将参数放入一个结果集(键值对),指令传参整体作为一个名为`payload`的json对象放入结果集,设备上传的报文则作为一个名为`bytebuf`的16进制字符串放入结果集 - 每一条转换规则执行前通过占位符`${参数名}`从结果集中获取对应参数替换掉占位符,执行后的结果都会放入结果集 - 转换规则包含`type`、`param`、`expression`三个参数,`type`表示管道类型,`param`表示输出参数名,`expression`表示表达式 #### Pipeline处理类 | 类型 | 类名 | 说明 | | :-------: | :--------------: | :--------: | | PARSE | ParseHandler | 解析 | | COMPUTE | ComputeHandler | 脚本 | | COMPOSE | ComposeHandler | 组装 | | ALGORITHM | AlgorithmHandler | 算法 | | SUBFLOW | SubflowHandler | 子流程 | | CACHE | CacheHandler | 缓存 | | MAPPING | MappingHandler | 映射 | | FILTER | FilterHandler | 过滤 | | INJECTION | InjectionHandler | 外部数据源 | 常用的是 PARSE、COMPUTE、COMPOSE,特殊情况下使用 ALGORITHM、SUBFLOW - PARSE 用来解析上行报文里的数据 `expression`各参数说明: <table> <tr> <th align="center">参数名</th> <th colspan=2 align="center">说明</th> </tr> <tr> <td align="center">start</td> <td colspan=2 align="center">表示数据起始字节在报文字节数组里的下标</td> </tr> <tr> <td rowspan=14 align="center">type</td> <td colspan=2 align="center">数据类型,不同数据类型对应不同字节数,<br>目前定义的数据类型如下: </td> </tr> <tr> <td align="center"> BIT </td> <td align="center"> 比特位 </td> </tr> <tr> <td align="center"> EIGHT_INT </td> <td align="center"> 八位有符号整型 </td> </tr> <tr> <td align="center"> U_EIGHT_INT </td> <td align="center"> 八位无符号整型 </td> </tr> <tr> <td align="center"> SIXTEEN_INT </td> <td align="center"> 十六位有符号整型 </td> </tr> <tr> <td align="center"> U_SIXTEEN_INT </td> <td align="center"> 十六位无符号整型 </td> </tr> <tr> <td align="center"> THIRTY_TWO_INT </td> <td align="center"> 三十二位有符号整型 </td> </tr> <tr> <td align="center"> U_THIRTY_TWO_INT </td> <td align="center"> 三十二位无符号整型 </td> </tr> <tr> <td align="center"> SIXTY_FOUR_INT </td> <td align="center"> 六十四位有符号整型 </td> </tr> <tr> <td align="center"> STRING </td> <td align="center"> ASCII码转字符串 </td> </tr> <tr> <td align="center"> SIXTEEN_BCD </td> <td align="center"> 十六位BCD码 </td> </tr> <tr> <td align="center"> EIGHT_BCD </td> <td align="center"> 八位BCD码 </td> </tr> <tr> <td align="center"> FLOAT </td> <td align="center"> 单精度浮点数,数据字节序 H4 H3 H2 H1 <br>(目前仅ARCM300-Z-4G、ARCM310-4G在用) </td> </tr> <tr> <td align="center"> IEEE754 </td> <td align="center"> 单精度浮点数 </td> </tr> <tr> <td align="center"> formula </td> <td colspan=2 align="center"> 数据源规则,一般放入需要解析的报文的16进制字符串 </td> </tr> <tr> <td align="center"> precision </td> <td colspan=2 align="center"> 精度,小数位,不填默认为0,<br>`type` 为浮点型只保留小数位,<br>`type` 为整型会先除以10^(precision)<br>再保留小数位 </td> </tr> <tr> <td align="center"> bit </td> <td colspan=2 align="center"> 表示在字节的的比特位,范围 0到7 </td> </tr> <tr> <td align="center"> endian </td> <td colspan=2 align="center"> 字节序,`BE` 表示高位在前 `LE` 表示低位在前,<br>不填默认高位在前</td> </tr> </table> ```js 示例: 解析16位无符号整型 { "type": "PARSE", "param": "Ua", "expression": "{'start':5,'type':'U_SIXTEEN_INT','formula':'${byteBuf}','precision':1}" } 解析单个字节里的比特位 { "type": "PARSE", "param": "SwitchSta", "expression": "{'start': 75,'type': 'BIT','formula':'${byteBuf}' ,'bit':7}" } 解析ASII码表示的字符串,如报文里的设备序列号 { "type": "PARSE", "param": "sn", "expression": "{'start': 3,'length': 20,'formula':'${byteBuf}','type': 'STRING'}" } ``` - COMPUTE 执行简单的js脚本 `expression`各参数说明: |参数名|说明| |:----:|:----:| |formula|简单的js脚本, 例如加减乘除、移位运算、三目运算符等| ```js 示例: 输出布尔值,作用是判断报文长度是否满足条件 { "type": "COMPUTE", "param": "lengthError", "expression": "{'formula':\"'${byteBuf}'.length>=202\"}" } 使用乘法运算 { "type": "COMPUTE", "param": "Balance", "expression": "{'formula':'${payload.Balance} * 100'}" } 使用乘法运算,输出结果保留3位小数 { "type": "COMPUTE", "param": "Pa", "expression": "{'formula':'Number((${Pa} * ${pt} * ${ct}).toFixed(3))'}" } 使用乘和除,结果保留2位小数 { "type": "COMPUTE", "param": "MEPIMD", "expression": "{'formula':'Number((${MEPIMD} * ${pt}* ${ct} / 1000).toFixed(2))'}" } 使用三目运算符,作用是表地址如果带下划线如 1_1 这种只截取下划线后的部分 { "type": "COMPUTE", "param": "addr", "expression": "{'formula':\"'${payload.addr}'.indexOf('_')>0?'${payload.addr}'.split('_')[1]:'${payload.addr}'\"}" } 使用位运算,作用是截取16位整型高位字节部分 { "type": "COMPUTE", "param": "port1", "expression": "{'formula':\"(${port}>>8)&255\"}" } 三目运算符和位运算结合使用 { "type": "COMPUTE", "param": "isHoliday0", "expression": "{'formula':\"'${payload.IsHoliday[0]}'=='true'?1<<1:0<<1\"}" } ``` - COMPOSE 主要用来拼接字符串、将传入的参数值转为16进制字符串 ```js 示例: 拼接简单字符串 { "type": "COMPOSE", "param": "data", "expression": "{'formula':'${data}${crc}'}" } 拼接json字符串 { "type": "COMPOSE", "param": "output", "expression": "{'formula':'{\"data\":\"${data}\",\"method\":\"${payload.method}\",\"key\":\"${sn}_${newAddr}_10\"}'}" } 将传入的值转为八位整型hex字符串,如 255 转为 ff,不满足两位的在前面补0,若 addr 带字母如`T10001`会导致报错 { "type": "COMPOSE", "param": "addr", "expression": "{'formula':'${addr}','outputFormat':'HEX','type':'EIGHT_INT'}" } 将传入的值转为无符号十六位整型hex字符串,如 1 转为 0001,不满足四位的在前面补0 { "type": "COMPOSE", "param": "PowerLimit", "expression": "{'formula':'${PowerLimit}','outputFormat':'HEX','type':'U_SIXTEEN_INT'}" } 取入参AlarmPower这个集合的第一个元素,转无符号十六位整型hex字符串 { "type": "COMPOSE", "param": "alarmPower1", "expression": "{'formula':'${payload.AlarmPower[0]}','outputFormat':'HEX','type':'U_SIXTEEN_INT'}" } ``` - ALGORITHM 算法,中台定义的特殊处理流程,由代码实现,根据表达式`expression`中的`method`属性区分使用何种算法,`param`入参内容由算法单独定义 已定义的算法列举如下: |名称|说明| |:----:|:----:| |CRC|CRC校验| |BYTES|获取指定开始位置的报文内容| |TIME_FORMAT|将秒级时间戳转为指定格式字符串| |TIME_FORMAT_MS|将毫秒级时间戳转为指定格式字符串| |BYTES_LENGTH|获取字节数组的长度| |CHECK_SUM|求校验和| |STR_TO_BCD|十进制字符串转BCD码字符串(默认高位在前)| |TIME_TO_645|时间字符串转645协议时间格式字符串| |IP_TO_HEX|ip地址转为4字节HEX字符串| |TIME_TO_BCD|时间转BCD字符串| |HEX_DATA_TO_645|645协议下行报文,入参HEX每个字节转BCD再加0x33,<br>输出结果为HEX字符串| |ASC_TO_HEX|将字符串如OTA升级的url转为ASCII码表示的HEX字符串| |WRITE_MODBUS_RTU_SINGLE_DATA|ModbusRTU协议写单个寄存器组报文| |WRITE_MODBUS_RTU_DATA|ModbusRTU协议写多个寄存器组报文| |WRITE_MODBUS_TCP_SINGLE_DATA|ModbusTCP协议写单个寄存器组报文| |WRITE_MODBUS_TCP_DATA|ModbusTCP协议写多个寄存器组报文| |WRITE_BYTE_DATA|安全用电协议批量写寄存器数据,<br>自动加外层大括号和0x90命令字,若不使用0x90命令字,配置cmd参数| ```js 示例: 计算crc,入参`param`须为HEX字符串,输出结果为两字节HEX字符串,低位在前高位在后 { "type" : "ALGORITHM", "param" : "crc", "expression" : "{'method':'CRC','param':'${data}'}" } 计算校验和,入参`param`须为HEX字符串,输出结果为单字节HEX字符串 { "type" : "ALGORITHM", "param" : "sum", "expression" : "{'method':'CHECK_SUM','param':'${data}'}" } 获取指定开始位置的报文内容,`start`为起始数组下标,必填,`end`为截止数组下标,`end`不填则从起始下标截取到报文末尾 { "type": "ALGORITHM", "param": "byteBuf", "expression": "{'method':'BYTES','param':'{\"start\":${start}}'}" } ModbusRTU协议写单个寄存器,入参`addr`为设备Modbus地址,16进制表示,`start`为起始寄存器地址,16进制表示,`value`为写进寄存器的值,16进制表示,输出结果为HEX字符串 { "type": "ALGORITHM", "param": "data", "expression": "{'method':'WRITE_MODBUS_RTU_SINGLE_DATA','param':'{\"addr\":\"${addr}\",\"start\":\"11\",\"value\":\"${TypeNum}\"}'}" } ModbusRTU协议写多个寄存器,入参`addr`为设备Modbus地址,16进制表示,`start`为起始寄存器地址,16进制表示,`len`为写寄存器长度,十进制表示,`value`为写进寄存器的值,HEX字符串格式,输出结果为HEX字符串 { "type": "ALGORITHM", "param": "data2", "expression": "{'method':'WRITE_MODBUS_RTU_DATA','param':'{\"addr\":\"${addr}\",\"start\":\"12\",\"len\":\"2\",\"value\":\"${data2}\"}'}" } 安全用电协议透传批量写寄存器组包,入参`addr`为设备Modbus地址,16进制表示,`start`为起始寄存器地址,16进制表示,`len`为写寄存器长度,十进制表示,`value`为写进寄存器的值,HEX字符串格式,输出结果为HEX字符串,自动加上{{90...crc}} { "type": "ALGORITHM", "param": "data1", "expression": "{'method':'WRITE_BYTE_DATA','param':'{\"addr\":\"${addr}\",\"start\":\"1234\",\"len\":\"10\",\"value\":\"${data1}\"}'}" } ``` - SUBFLOW 子流程,复杂的处理流程,由代码实现,根据表达式`expression`中的`method`属性区分使用哪个子流程,`param`入参内容由子流程单独定义 已定义的子流程列举如下: |名称|说明| |:----:|:----:| |PREPAYMENT_PROTOCOL|预付费安全用电协议实时数据91报文解析| |PREPAYMENT_CONTROL|预付费安全用电协议透传指令响应报文解析| |BUILDING_PROTOCOL|ANet预付费建筑能耗协议透传指令响应报文解析| |MQTTCONTROL_PROTOCOL|海外mqtt协议透传指令响应报文解析| |SAFE_GATEWAY_PROTOCOL|安全用电网关协议上行报文解析(7b7b...[[1-1((...))]]...7d7d)| |SAFE_PROTOCOL|安全用电协议上行特殊报文解析,如ARCM300-Z-4G 92报文| |SAFE_CONTROL|安全用电协议透传指令响应报文处理| |SAFE_ELECTRIC_ALARM|安全用电协议告警判断子流程| |MULTIRATETIMESET|复费率时段设置透传报文组包| |READMULTIRATETIME|复费率时段读取透传报文组包| ```js 示例: 预付费安全用电协议实时数据91报文解析子流程,在`GSM500`网关型号上行解析规则中,输出结果为解析的设备实时数据 { "type": "SUBFLOW", "param": "report", "expression": "{'method':'PREPAYMENT_PROTOCOL'}" } 预付费安全用电协议透传抄表03指令回包解析处理,在`GSM500`网关型号上行解析规则中,`param`为子设备在平台的实际仪表地址,用于查询子设备型号的解析规则进而解析报文 { "type": "SUBFLOW", "param": "report", "expression": "{'method':'PREPAYMENT_CONTROL','param':'${newAddr}'}" } 安全用电协议判断报警,在`ARCM300-Z-4G`上行解析规则中,`param`参数名`UHigh2`对应中台数据库`xch_AlarmInfo`报警编码表里的过压告警,`expression`表达式里的`formula`参数为报警判断条件,`expression`表达式里的`param`参数为中台协议alarm报文中的报警详情 { "type": "SUBFLOW", "param": "UHigh2", "expression": "{'method':'SAFE_ELECTRIC_ALARM','formula':\"${AST.UHigh2}==1&&${CACHE.[0].UHigh2}==0?1:0\",'param':'{\"addr\":1,\"alarmType\":\"HIGH\",\"currentValue\":\"\"}'}" } 设置复费率时段组包,在`DTSY`下行解析规则中,`expression`.`param`.`method`传入平台下发的`method`,用来区分下发几时区几时段,`expression`.`param`.`addr`传入16进制Modbus地址,`expression`.`param`.`payload`传入平台下发到中台的完整json参数 `expression`.`param`.`zoneNumStartAddrs`传入一个集合,里面的第一个元素是第一套时区时段表号寄存器地址,第二个元素是第五套时区时段表号寄存器地址 `expression`.`param`.`zoneNumStartAddrs`传入一个集合,里面的元素按顺序分别是1-n套时段表的起始寄存器地址,`expression`.`param`.`dayMonth`和`expression`.`param`.`minuteHour`用来区分报文日月、分时字节序是否日在月前、分在时前,不填默认为true,低位在前 最终输出结果是多条报文由`&&`拼接的一个字符串,报文顺序遵循时区时段表号和时区起始日期在前,时段表报文在后 { "type": "SUBFLOW", "param": "data", "expression": "{'method':'MULTIRATETIMESET','param':'{\"method\":\"${payload.method}\",\"addr\":\"${addr}\",\"payload\":${payload},\"zoneNumStartAddrs\":[\"E000\",\"E006\"],\"tableStartAddrs\":[\"E02A\",\"E03F\",\"E054\",\"E069\",\"E07E\",\"E093\",\"E0A8\",\"E0BD\"],\"dayMonth\":false,\"minuteHour\":false}'}" } 读取复费率时段组包,在`DTSY`下行解析规则中,`expression`.`param`入参同复费率时段设置 { "type": "SUBFLOW", "param": "data", "expression": "{'method':'READMULTIRATETIME','param':'{\"method\":\"${payload.method}\",\"addr\":\"${addr}\",\"payload\":${payload},\"zoneNumStartAddrs\":[\"03b2\",\"082a\"],\"tableStartAddrs\":[\"03b8\",\"03cd\",\"0800\",\"0815\"],\"dayMonth\":true,\"minuteHour\":true}'}" } ``` - CACHE 缓存,一般用来缓存仪表的告警标志位,当下一次解析数据报文时,可以用来判断报警和复位。 ```js 示例: 将结果集中的AST对象放入大小为1的队列中,后续放入的AST对象都会覆盖上一次的 { "type": "CACHE", "expression": "{\"prop\": \"AST\",\"addr\":\"${addr}\",\"type\": \"QUEUE\",\"size\": 1}" } ```
王旭东
2024年12月27日 09:27
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码