透传设备接入完善

V0.5.x
xiwa 2022-12-13 07:15:44 +08:00
parent 986d6031e8
commit e67129dec7
18 changed files with 276 additions and 36 deletions

View File

@ -115,7 +115,7 @@ this.encode = function (service,device) {
var rst=component.transparentEncode(service,device);
topic="/sys/"+rst.productKey+"/"+rst.deviceName+"/c/service/rawSend";
params.model=rst.content.model;
params.mac=rst.content.mac;
params.deviceName=rst.content.deviceName;
params.data=rst.content.data;
return {

View File

@ -104,17 +104,19 @@
"length": "10240"
}
},
"name": "数据"
"name": "数据",
"required": false
},
{
"identifier": "mac",
"identifier": "deviceName",
"dataType": {
"type": "text",
"specs": {
"length": "128"
}
},
"name": "设备mac"
"name": "设备唯一码",
"required": false
},
{
"identifier": "model",
@ -124,7 +126,8 @@
"length": "128"
}
},
"name": "设备型号"
"name": "设备型号",
"required": false
}
],
"outputData": [],
@ -143,17 +146,19 @@
"length": "10240"
}
},
"name": "数据"
"name": "数据",
"required": false
},
{
"identifier": "mac",
"identifier": "deviceName",
"dataType": {
"type": "text",
"specs": {
"length": "128"
}
},
"name": "设备mac"
"name": "设备唯一码",
"required": false
},
{
"identifier": "model",
@ -163,7 +168,8 @@
"length": "128"
}
},
"name": "设备型号"
"name": "设备型号",
"required": false
}
],
"name": "透传上报"

View File

@ -10,19 +10,66 @@
package cc.iotkit.comp.emqx;
import cc.iotkit.common.thing.ThingService;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.product.ProductModel;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import javax.script.ScriptEngineManager;
import java.util.Map;
@Slf4j
@Data
public class JsScripter implements IScripter {
private ProductModel model;
private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn");
private Object scriptObj;
public JsScripter(ProductModel model) {
this.model = model;
}
@Override
public void setScript(String script) {
try {
scriptObj = engine.eval(String.format("new (function () {\n%s})()", script));
} catch (Throwable e) {
throw new RuntimeException("init script error", e);
}
}
public ThingModelMessage decode(TransparentMsg msg) {
return null;
try {
ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "decode", msg);
ThingModelMessage message = new ThingModelMessage();
BeanUtils.populate(message, result);
return message;
} catch (Throwable e) {
log.error("invoke decode script error", e);
return null;
}
}
public TransparentMsg encode(ThingService<?> service) {
return null;
try {
ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "encode", service);
Map map = (Map) JsonUtil.toObject(result);
TransparentMsg message = new TransparentMsg();
BeanUtils.populate(message, map);
message.setProductKey(model.getProductKey());
message.setModel(model.getModel());
message.setDeviceName(service.getDeviceName());
return message;
} catch (Throwable e) {
log.error("invoke encode script error", e);
return null;
}
}
}

View File

@ -11,6 +11,8 @@ package cc.iotkit.comp.emqx;
import cc.iotkit.common.thing.ThingService;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.product.ProductModel;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.luaj.vm2.LuaTable;
@ -27,14 +29,21 @@ import java.util.List;
import java.util.Map;
@Slf4j
@Data
public class LuaScripter implements IScripter {
private ProductModel model;
private final LuaScriptEngine engine = (LuaScriptEngine) (
new ScriptEngineManager().getEngineByName("luaj"));
private LuaValue decoder;
private LuaValue encoder;
public LuaScripter(ProductModel model) {
this.model = model;
}
@Override
public void setScript(String script) {
try {
@ -52,14 +61,14 @@ public class LuaScripter implements IScripter {
try {
LuaTable table = new LuaTable();
table.set("model", msg.getModel());
table.set("mac", msg.getMac());
table.set("deviceName", msg.getDeviceName());
table.set("data", msg.getData());
Map result = (Map) parse(decoder.call(table));
ThingModelMessage modelMessage = new ThingModelMessage();
BeanUtils.populate(modelMessage, result);
modelMessage.setProductKey(msg.getProductKey());
modelMessage.setDeviceName(msg.getMac());
modelMessage.setDeviceName(msg.getDeviceName());
return modelMessage;
} catch (Throwable e) {
log.error("execute decode script error", e);
@ -85,6 +94,9 @@ public class LuaScripter implements IScripter {
Map map = (Map) parse(result);
TransparentMsg message = new TransparentMsg();
BeanUtils.populate(message, map);
message.setProductKey(model.getProductKey());
message.setModel(model.getModel());
message.setDeviceName(service.getDeviceName());
return message;
} catch (Throwable e) {
log.error("execute encode script error", e);

View File

@ -20,6 +20,7 @@ import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.product.ProductModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
@ -37,10 +38,13 @@ public class TransparentConverter {
*
*/
public ThingModelMessage decode(TransparentMsg msg) {
//通过上报消息中的model取得对应的产品
String productKey = checkScriptUpdate(msg.getModel());
String productKey = msg.getProductKey();
productKey = checkScriptUpdate(productKey, msg.getModel());
msg.setProductKey(productKey);
return scripters.get(productKey).decode(msg);
ThingModelMessage decodeMsg = scripters.get(productKey).decode(msg);
decodeMsg.setProductKey(msg.getProductKey());
decodeMsg.setDeviceName(msg.getDeviceName());
return decodeMsg;
}
/**
@ -48,7 +52,7 @@ public class TransparentConverter {
*/
public DeviceMessage encode(ThingService<?> service, Device device) {
String productKey = service.getProductKey();
checkScriptUpdate(device.getModel());
checkScriptUpdate(productKey, device.getModel());
TransparentMsg transparentMsg = scripters.get(productKey).encode(service);
//转换成网关消息
String deviceName = service.getDeviceName();
@ -82,8 +86,19 @@ public class TransparentConverter {
/**
*
*/
private String checkScriptUpdate(String model) {
ProductModel productModel = getScript(model);
private String checkScriptUpdate(String pk, String model) {
ProductModel productModel = null;
if (StringUtils.isNotBlank(model)) {
productModel = getScript(model);
}
//指定型号获取不到获取默认型号
if (productModel == null && StringUtils.isNotBlank(pk)) {
productModel = getScript(ProductModel.getDefaultModel(pk));
}
if (productModel == null) {
throw new RuntimeException("product model script does not exist");
}
String productKey = productModel.getProductKey();
String script = productModel.getScript();
@ -94,9 +109,9 @@ public class TransparentConverter {
String type = productModel.getType();
if (ProductModel.TYPE_LUA.equals(type)) {
scripters.putIfAbsent(productKey, new LuaScripter());
scripters.putIfAbsent(productKey, new LuaScripter(productModel));
} else if (ProductModel.TYPE_JS.equals(type)) {
scripters.putIfAbsent(productKey, new JsScripter());
scripters.putIfAbsent(productKey, new JsScripter(productModel));
}
//更新脚本

View File

@ -23,7 +23,7 @@ public class TransparentMsg {
private String model;
private String mac;
private String deviceName;
private String data;

View File

@ -11,9 +11,12 @@ package cc.iotkit.comp.mqtt;
import cc.iotkit.common.thing.ThingService;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.product.ProductModel;
public interface IScripter {
void setModel(ProductModel model);
void setScript(String script);
/**

View File

@ -10,19 +10,66 @@
package cc.iotkit.comp.mqtt;
import cc.iotkit.common.thing.ThingService;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.product.ProductModel;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import javax.script.ScriptEngineManager;
import java.util.Map;
@Slf4j
@Data
public class JsScripter implements IScripter {
private ProductModel model;
private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn");
private Object scriptObj;
public JsScripter(ProductModel model) {
this.model = model;
}
@Override
public void setScript(String script) {
try {
scriptObj = engine.eval(String.format("new (function () {\n%s})()", script));
} catch (Throwable e) {
throw new RuntimeException("init script error", e);
}
}
public ThingModelMessage decode(TransparentMsg msg) {
return null;
try {
ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "decode", msg);
ThingModelMessage message = new ThingModelMessage();
BeanUtils.populate(message, result);
return message;
} catch (Throwable e) {
log.error("invoke decode script error", e);
return null;
}
}
public TransparentMsg encode(ThingService<?> service) {
return null;
try {
ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "encode", service);
Map map = (Map) JsonUtil.toObject(result);
TransparentMsg message = new TransparentMsg();
BeanUtils.populate(message, map);
message.setProductKey(model.getProductKey());
message.setModel(model.getModel());
message.setDeviceName(service.getDeviceName());
return message;
} catch (Throwable e) {
log.error("invoke encode script error", e);
return null;
}
}
}

View File

@ -11,6 +11,8 @@ package cc.iotkit.comp.mqtt;
import cc.iotkit.common.thing.ThingService;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.product.ProductModel;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.luaj.vm2.LuaTable;
@ -27,14 +29,21 @@ import java.util.List;
import java.util.Map;
@Slf4j
@Data
public class LuaScripter implements IScripter {
private ProductModel model;
private final LuaScriptEngine engine = (LuaScriptEngine) (
new ScriptEngineManager().getEngineByName("luaj"));
private LuaValue decoder;
private LuaValue encoder;
public LuaScripter(ProductModel model) {
this.model = model;
}
@Override
public void setScript(String script) {
try {
@ -52,14 +61,14 @@ public class LuaScripter implements IScripter {
try {
LuaTable table = new LuaTable();
table.set("model", msg.getModel());
table.set("mac", msg.getMac());
table.set("deviceName", msg.getDeviceName());
table.set("data", msg.getData());
Map result = (Map) parse(decoder.call(table));
ThingModelMessage modelMessage = new ThingModelMessage();
BeanUtils.populate(modelMessage, result);
modelMessage.setProductKey(msg.getProductKey());
modelMessage.setDeviceName(msg.getMac());
modelMessage.setDeviceName(msg.getDeviceName());
return modelMessage;
} catch (Throwable e) {
log.error("execute decode script error", e);
@ -85,6 +94,9 @@ public class LuaScripter implements IScripter {
Map map = (Map) parse(result);
TransparentMsg message = new TransparentMsg();
BeanUtils.populate(message, map);
message.setProductKey(model.getProductKey());
message.setModel(model.getModel());
message.setDeviceName(service.getDeviceName());
return message;
} catch (Throwable e) {
log.error("execute encode script error", e);

View File

@ -20,6 +20,7 @@ import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.product.ProductModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
@ -37,10 +38,13 @@ public class TransparentConverter {
*
*/
public ThingModelMessage decode(TransparentMsg msg) {
//通过上报消息中的model取得对应的产品
String productKey = checkScriptUpdate(msg.getModel());
String productKey = msg.getProductKey();
productKey = checkScriptUpdate(productKey, msg.getModel());
msg.setProductKey(productKey);
return scripters.get(productKey).decode(msg);
ThingModelMessage decodeMsg = scripters.get(productKey).decode(msg);
decodeMsg.setProductKey(msg.getProductKey());
decodeMsg.setDeviceName(msg.getDeviceName());
return decodeMsg;
}
/**
@ -48,7 +52,7 @@ public class TransparentConverter {
*/
public DeviceMessage encode(ThingService<?> service, Device device) {
String productKey = service.getProductKey();
checkScriptUpdate(device.getModel());
checkScriptUpdate(productKey, device.getModel());
TransparentMsg transparentMsg = scripters.get(productKey).encode(service);
//转换成网关消息
String deviceName = service.getDeviceName();
@ -82,8 +86,19 @@ public class TransparentConverter {
/**
*
*/
private String checkScriptUpdate(String model) {
ProductModel productModel = getScript(model);
private String checkScriptUpdate(String pk, String model) {
ProductModel productModel = null;
if (StringUtils.isNotBlank(model)) {
productModel = getScript(model);
}
//指定型号获取不到获取默认型号
if (productModel == null && StringUtils.isNotBlank(pk)) {
productModel = getScript(ProductModel.getDefaultModel(pk));
}
if (productModel == null) {
throw new RuntimeException("product model script does not exist");
}
String productKey = productModel.getProductKey();
String script = productModel.getScript();
@ -94,9 +109,9 @@ public class TransparentConverter {
String type = productModel.getType();
if (ProductModel.TYPE_LUA.equals(type)) {
scripters.putIfAbsent(productKey, new LuaScripter());
scripters.putIfAbsent(productKey, new LuaScripter(productModel));
} else if (ProductModel.TYPE_JS.equals(type)) {
scripters.putIfAbsent(productKey, new JsScripter());
scripters.putIfAbsent(productKey, new JsScripter(productModel));
}
//更新脚本

View File

@ -23,7 +23,7 @@ public class TransparentMsg {
private String model;
private String mac;
private String deviceName;
private String data;

View File

@ -46,6 +46,7 @@ public class CacheConfig {
Constants.CACHE_CATEGORY, config,
Constants.CACHE_THING_MODEL, config,
Constants.CACHE_SPACE, config,
Constants.CACHE_PRODUCT_SCRIPT, config,
//统计缓存5分钟
Constants.CACHE_DEVICE_STATS, config.entryTtl(Duration.ofMinutes(5))
);

View File

@ -49,4 +49,8 @@ public class ProductModel implements Id<String> {
private Long modifyAt;
public static String getDefaultModel(String pk) {
return pk + "_default";
}
}

View File

@ -57,6 +57,7 @@ public class ProductController {
@Autowired
private AliyunConfig aliyunConfig;
@Autowired
@Qualifier("productModelDataCache")
private IProductModelData productModelData;
@Autowired
private IDbStructureData dbStructureData;

View File

@ -0,0 +1,76 @@
/*
* +----------------------------------------------------------------------
* | Copyright (c) 2021-2022 All rights reserved.
* +----------------------------------------------------------------------
* | Licensed
* +----------------------------------------------------------------------
* | Author: xw2sy@163.com
* +----------------------------------------------------------------------
*/
package cc.iotkit.test.mqtt.example;
import cc.iotkit.test.mqtt.config.Mqtt;
import cc.iotkit.test.mqtt.model.Request;
import cc.iotkit.test.mqtt.service.Gateway;
import cc.iotkit.test.mqtt.service.ReportTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*
*/
@Slf4j
public class TransparentTest {
public static void main(String[] args) throws IOException {
if (args.length == 0) {
Mqtt.brokerHost = "127.0.0.1";
// Mqtt.brokerHost = "120.76.96.206";
// Mqtt.brokerHost = "172.16.1.109";
} else {
Mqtt.brokerHost = args[0];
}
log.info("start gateway ");
Gateway gateway = new Gateway("hbtgIA0SuVw9lxjB",
"TEST:GW:T0001");
gateway.addSubDevice("",
"TEST_LIGHT_0001",
"M1");
gateway.onDeviceOnline((device) -> {
String pk = device.getProductKey();
//设备上线后添加上报定时任务
ReportTask reportTask = new ReportTask(gateway.getClient());
reportTask.addTask(String.format("/sys/%s/%s/s/event/rawReport",
pk, device.getDeviceName()),
() -> {
Request request = new Request();
request.setId(UUID.randomUUID().toString());
request.setMethod("thing.event.rawReport");
Map<String, Object> param = new HashMap<>();
param.put("model", "M1");
param.put("deviceName", "TEST_LIGHT_0001");
param.put("data", "111110011");
request.setParams(param);
return request;
});
reportTask.start(10);
});
gateway.start();
System.in.read();
}
}

View File

@ -58,10 +58,11 @@ public class MessageHandler implements Handler<MqttPublishMessage> {
if (response.getCode() == 0) {
Map<String, Object> data = response.getData();
String productKey = data.get("productKey").toString();
String deviceName = data.get("deviceName").toString();
if (StringUtils.isBlank(productKey)) {
deviceOnlineListener.accept(new Device(productKey, deviceName, ""));
return;
}
String deviceName = data.get("deviceName").toString();
//订阅子设备消息
String subTopic = String.format("/sys/%s/%s/c/#", productKey, deviceName);