1、腳本語(yǔ)言
Tips
規(guī)則腳本采用Groovy編寫,是一種基于JVM(Java虛擬機(jī))的敏捷開發(fā)語(yǔ)言,Groovy代碼能夠與Java代碼很好的結(jié)合,也能用于擴(kuò)展現(xiàn)有代碼。
Groovy的語(yǔ)法與 Java 語(yǔ)言的語(yǔ)法很相似,完成同樣的任務(wù)所需的代碼比 Java 代碼更少??梢詫⑺胂癯?Java 語(yǔ)言的一種更加簡(jiǎn)單、表達(dá)能力更強(qiáng)的變體,基本上可以直接使用Java代碼編寫腳本。
2、新建規(guī)則腳本
規(guī)則腳本列表
編輯規(guī)則腳本
配置說明:
- 腳本事件:設(shè)備上報(bào)(已支持)、服務(wù)下發(fā)(已支持)、設(shè)備上線、設(shè)備離線
- 腳本動(dòng)作:消息重發(fā)(已支持)、消息通知、Http推送、mqtt橋接、數(shù)據(jù)庫(kù)存儲(chǔ)
- 所屬產(chǎn)品:規(guī)則腳本跟產(chǎn)品綁定,只會(huì)影響產(chǎn)品下面的設(shè)備
- 腳本順序:產(chǎn)品下面有多個(gè)腳本,按照順序執(zhí)行
3、規(guī)則腳本基礎(chǔ)示例
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.util.NumberUtil;
// 1. 獲取主題/消息內(nèi)容/設(shè)備編號(hào)/協(xié)議編碼
String topic = msgContext.getTopic();
String payload = msgContext.getPayload();
String serialNumber = msgContext.getSerialNumber();
String protocolCode = msgContext.getProtocolCode();
// 2. 數(shù)據(jù)轉(zhuǎn)換(自己處理)
msgContext.logger.info("數(shù)據(jù)轉(zhuǎn)換處理")
String NewTopic = topic;
String NewPayload = payload;
// 3. 返回新的數(shù)據(jù)
msgContext.setTopic(NewTopic);
msgContext.setPayload(NewPayload);
Tips
- 默認(rèn)僅使用hutool的Json處理和數(shù)字工具類庫(kù),hutool其他類庫(kù)或者系統(tǒng)相關(guān)類庫(kù),需要后端開放一下;
- 默認(rèn)禁止使用For/While循環(huán)和IO操作等,根據(jù)情況可以后端開放;
- 通過msgContext獲取和設(shè)置主題和消息內(nèi)容;
- 主題和消息內(nèi)容如何轉(zhuǎn)換需要自己編寫。
規(guī)則腳本通過上下文 MsgContext
存取數(shù)據(jù)。腳本中可以通過 msgContext
獲取值和重新設(shè)置新的值,系統(tǒng)定義的上下文如下:
public class MsgContext {
/** 消息主題 */
private String topic;
/** 消息內(nèi)容 */
private String payload;
/** 設(shè)備編號(hào) */
private String serialNumber;
/** 產(chǎn)品ID */
private Long productId;
/** 協(xié)議編碼 */
private String protocolCode;
}
4. 設(shè)備上報(bào)示例
我們創(chuàng)建一個(gè)產(chǎn)品,產(chǎn)品選擇JSON協(xié)議

按照平臺(tái)處理上報(bào)數(shù)據(jù)的系統(tǒng)主題和系統(tǒng)數(shù)據(jù)格式分別是:
Topic: /96/D1ELV3A5TOJS/property/post
[
{
"id": "temperature",
"value": "26.45"
},
{
"id": "humidity",
"value": "65.8"
}
]
實(shí)際設(shè)備上報(bào)的數(shù)據(jù)格式和主題分別是:
Topic: D1ELV3A5TOJS/post
{
"temperature": 26.5,
"humidity": 65.8
}
此時(shí),我們使用腳本轉(zhuǎn)換主題和數(shù)據(jù)格式,我們新建一個(gè)腳本

腳本內(nèi)容如下:
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.util.NumberUtil;
//系統(tǒng)主題
String sysTopic = '';
//系統(tǒng)數(shù)據(jù)格式
String sysPayload = '';
// 1. 獲取主題和內(nèi)容,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("產(chǎn)品id/協(xié)議編號(hào):" + productId + " / " + protocolCode);
// 2. 轉(zhuǎn)換為系統(tǒng)主題 /96/D1ELV3A5TOJS/property/post
sysTopic = "/" + productId + "/" + serialNumber + "/property/post"
if("JSON".equals(protocolCode)){
// 3. 內(nèi)容格式轉(zhuǎn)換
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{
//其他協(xié)議處理
}
// 4.打印
msgContext.logger.info("新主題:" + sysTopic);
msgContext.logger.info("新內(nèi)容:" + sysPayload);
// 5. 返回新的數(shù)據(jù)(必要)
msgContext.setTopic(sysTopic)
msgContext.setPayload(sysPayload);
腳本內(nèi)容基本比較容易理解。我們編輯好腳本后,進(jìn)行驗(yàn)證。運(yùn)行一下看看效果。連接設(shè)備編號(hào)為:S&D1PGLPG58K66 的設(shè)備,按照如下格式發(fā)送:

我們看看腳本執(zhí)行后的在控制臺(tái)打印的結(jié)果:
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(消息轉(zhuǎn)發(fā))] execution
----------------------------------------------------------------------------------------
產(chǎn)品id/協(xié)議編號(hào):41 / JSON
新主題:/41/D1ELV3A5TOJS/property/post
新內(nèi)容:[{"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(消息轉(zhuǎn)發(fā))] 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[消息轉(zhuǎn)發(fā)]<0>
可以看到topic和數(shù)據(jù)格式已經(jīng)轉(zhuǎn)換為系統(tǒng)主題和格式
5. 服務(wù)下發(fā)轉(zhuǎn)換示例
假設(shè)實(shí)際設(shè)備服務(wù)下發(fā)的主題和數(shù)據(jù)格式分別是:
Topic: D1PGLPG58KZ2/set
{
"report_monitor": "4"
}
平臺(tái)系統(tǒng)主題和數(shù)據(jù)格式:
Topic: /96/D1PGLPG58K66/property/post
[
{
"id": "temperature",
"value": "26.45"
},
{
"id": "humidity",
"value": "65.8"
}
]
新增腳本,定義如下:

我們看看腳本的定義內(nèi)容:
1.將系統(tǒng)主題轉(zhuǎn)為真實(shí)設(shè)備需要的主題
2.將系統(tǒng)數(shù)據(jù)格式轉(zhuǎn)為真實(shí)設(shè)備需要的主題(注意:主題轉(zhuǎn)換時(shí) 設(shè)備編號(hào)必須帶上且長(zhǎng)度大于9位,如果不帶設(shè)備編號(hào),需要修改后端代碼)
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.util.NumberUtil;
//系統(tǒng)主題
String tranTopic = '';
//系統(tǒng)數(shù)據(jù)格式
String tranPayload = '';
// 1. 獲取主題和內(nèi)容
String topic = msgContext.getTopic();
String payload = msgContext.getPayload();
Long productId = msgContext.getProductId();
String serialNumber = msgContext.getSerialNumber();
String protocolCode = msgContext.getProtocolCode();
// 2. topic轉(zhuǎn)換 將/60/DEVICE555/function/get 系統(tǒng)主題 轉(zhuǎn)為 DEVICE555/set
tranTopic = serialNumber+ "/set";
if("JSON".equals(protocolCode)){
// 3. 轉(zhuǎn)發(fā)的數(shù)據(jù) {"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{
//其他協(xié)議處理
}
// 4.打印
msgContext.logger.info("轉(zhuǎn)發(fā)主題:" + tranTopic);
msgContext.logger.info("轉(zhuǎn)發(fā)內(nèi)容:" + tranPayload);
// 5. 返回新的數(shù)據(jù)(必要)
msgContext.setTopic(tranTopic);
msgContext.setPayload(tranPayload);
我們下發(fā)指令來測(cè)試一下轉(zhuǎn)換情況,后端日志內(nèi)容如下:
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(平臺(tái)下發(fā)轉(zhuǎn)發(fā))] execution
-------------------------------------------------
轉(zhuǎn)發(fā)主題:D1PGLPG58KZ2/set
轉(zhuǎn)發(fā)內(nèi)容:{"report_monitor":"6"}
-----------------------------------------------
17:34:36.440 [functionInvokeTask2] INFO c.y.l.c.ScriptCommonComponent - [info,200] - [6481bf113e15499aabe550189d16f4a5]:component[D1753673875549458432(平臺(tái)下發(fā)轉(zhuǎn)發(fā))] finished in 0 milliseconds
17:34:36.440 [functionInvokeTask2] INFO c.y.l.slot.Slot - [info,200] - [6481bf113e15499aabe550189d16f4a5]:CHAIN_NAME[dataChain]
客戶端訂閱接收內(nèi)容如下:

至此,將系統(tǒng)主題和數(shù)據(jù)格式轉(zhuǎn)換為設(shè)備所需主題和格式驗(yàn)證成功。