commit
1a68bb86e4
|
@ -0,0 +1,6 @@
|
|||
FROM openjdk:11-jre-slim
|
||||
WORKDIR /app
|
||||
ADD iot-standalone/target/iot-standalone-0.3.2-SNAPSHOT.tar /app/
|
||||
ADD /data /app/data/
|
||||
EXPOSE 8086
|
||||
ENTRYPOINT ["java", "-classpath", ".:lib/*","cc.iotkit.manager.Application"]
|
15
README.md
15
README.md
|
@ -16,7 +16,7 @@
|
|||
|
||||
系统包含了品类、物模型、消息转换、通讯组件(mqtt/EMQX通讯组件、小度音箱接入组件、onenet Studio接入组件)、云端低代码设备开发、设备管理、设备分组、规则引擎、第三方平台接入、数据流转、数据可视化、报警中心等模块和智能家居APP(小程序),集成了[Sa-Token](https://gitee.com/dromara/sa-token) 认证框架。
|
||||
|
||||
**前端项目见:** https://gitee.com/iotkit-open-source/iot-console-web
|
||||
**前端项目见:** https://gitee.com/iotkit-open-source/iot-console-web
|
||||
|
||||
**演示地址:** [演示地址](http://120.76.96.206),账号:guest1,密码:guest123 (只读权限)
|
||||
|
||||
|
@ -24,8 +24,10 @@
|
|||
|
||||
**小度接入:** 小度APP添加设备中搜索 奇特物联
|
||||
|
||||
**小度接入:** 小度APP添加设备中搜索 奇特物联
|
||||
|
||||
**系统截图**
|
||||
|
||||
**系统截图**
|
||||
![输入图片说明](doc/screenshot.jpg)
|
||||
|
||||
|
||||
|
@ -38,7 +40,7 @@
|
|||
|
||||
管理员账号密码:iotkit/iotkitadmin
|
||||
|
||||
**注:** 内置es在修改设备组时会报错,此时需要换成外置的es
|
||||
**注:** 内置es在修改设备组时会报错,此时需要换成外置的es
|
||||
|
||||
|
||||
#### 运行步骤
|
||||
|
@ -48,6 +50,11 @@
|
|||
|
||||
3、在iot-standalone模块的Application类上右键运行
|
||||
|
||||
#### docker运行
|
||||
git clone https://gitee.com/iotkit-open-source/iotkit-parent.git && cd iotkit-parent/docker-compose && docker-compose up -d
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### 技术文档
|
||||
|
@ -67,7 +74,7 @@ https://ztktkv.yuque.com/books/share/b96f1fee-41d8-4da3-9e22-b73aeb1e29ed?# 《i
|
|||
|
||||
微信群:
|
||||
|
||||
![输入图片说明](doc/ma.png)
|
||||
![输入图片说明](doc/ma.png)
|
||||
|
||||
|
||||
### roadmap
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
//api配置
|
||||
apiTool.config("127.0.0.1",8085,3000);
|
||||
|
||||
this.onReceive=function(method,path,header,params,body){
|
||||
//method:post、get、delete...
|
||||
//path:请求路径
|
||||
//header:http请求头数据,结构:{xx:xx,yy:yy}
|
||||
//params:请求参数,结构:{xx:[...],yy:[...]}
|
||||
//body:请求体,当提交的数据为json格式时使用,结构:{xx:xx,yy:yy}
|
||||
apiTool.log("onReceive body:"+body);
|
||||
var duHeader=body.header;
|
||||
var namespace=duHeader.namespace;
|
||||
var requestName=duHeader.name;
|
||||
var messageId=duHeader.messageId;
|
||||
var duPayload=body.payload;
|
||||
var token=duPayload.accessToken;
|
||||
var openUid=duPayload.openUid;
|
||||
|
||||
//设备发现
|
||||
if(namespace=="DuerOS.ConnectedHome.Discovery" && requestName=="DiscoverAppliancesRequest"){
|
||||
var deviceIds=[];
|
||||
var discoveredDevices=[];
|
||||
var content={
|
||||
header:{
|
||||
namespace:"DuerOS.ConnectedHome.Discovery",
|
||||
name:"DiscoverAppliancesResponse",
|
||||
messageId:messageId,
|
||||
payloadVersion:1
|
||||
},
|
||||
payload:{
|
||||
discoveredAppliances:discoveredDevices,
|
||||
discoveredGroups:[{
|
||||
groupName:"客厅",
|
||||
applianceIds:deviceIds,
|
||||
groupNotes:"客厅分组控制",
|
||||
additionalGroupDetails:{}
|
||||
}]
|
||||
}
|
||||
};
|
||||
var rst=apiTool.getSpaceDevices(token);
|
||||
apiTool.log(JSON.stringify(rst));
|
||||
if(rst && rst.status==200 && rst.data){
|
||||
var devices=rst.data;
|
||||
for(var i in devices){
|
||||
var device=devices[i];
|
||||
var did=device.deviceId;
|
||||
var pk=device.productKey;
|
||||
var dn=device.deviceName;
|
||||
|
||||
//更新设备openUid
|
||||
rst=apiTool.setOpenUid(token,did,"dueros",openUid);
|
||||
if(!rst || rst.status!=200){
|
||||
continue;
|
||||
}
|
||||
|
||||
//插座
|
||||
if(pk=="cGCrkK7Ex4FESAwe"){
|
||||
var powerstate=device.property.powerstate;
|
||||
discoveredDevices.push({
|
||||
actions:["turnOn","turnOff"],
|
||||
applianceTypes:["SOCKET"],
|
||||
additionalApplianceDetails:{},
|
||||
applianceId:device.deviceId,
|
||||
friendlyDescription:"智能插座",
|
||||
friendlyName:device.name,
|
||||
isReachable:device.online,
|
||||
manufacturerName:"海曼",
|
||||
modelName:"S1",
|
||||
version:"v1.0",
|
||||
attributes:[
|
||||
{
|
||||
name:"客厅的插座",
|
||||
scale:"",
|
||||
timestampOfSample:0,
|
||||
uncertaintyInMilliseconds:10
|
||||
},
|
||||
{
|
||||
name:"connectivity",
|
||||
value:"REACHABLE",
|
||||
scale:"",
|
||||
timestampOfSample:0,
|
||||
uncertaintyInMilliseconds:10
|
||||
},
|
||||
{
|
||||
name:"turnOnState",
|
||||
value:powerstate==1?"ON":"OFF",
|
||||
scale:"",
|
||||
timestampOfSample:0,
|
||||
uncertaintyInMilliseconds:10,
|
||||
legalValue:"(ON, OFF)"
|
||||
}
|
||||
]
|
||||
});
|
||||
}else if(pk=="Rf4QSjbm65X45753"){
|
||||
//开关
|
||||
var powerstate=device.property.powerstate;
|
||||
discoveredDevices.push({
|
||||
actions:["turnOn","turnOff"],
|
||||
applianceTypes:["SWITCH"],
|
||||
additionalApplianceDetails:{},
|
||||
applianceId:device.deviceId,
|
||||
friendlyDescription:"智能开关",
|
||||
friendlyName:device.name,
|
||||
isReachable:device.online,
|
||||
manufacturerName:"海曼",
|
||||
modelName:"S1",
|
||||
version:"v1.0",
|
||||
attributes:[
|
||||
{
|
||||
name:"客厅的开关",
|
||||
scale:"",
|
||||
timestampOfSample:0,
|
||||
uncertaintyInMilliseconds:10
|
||||
},
|
||||
{
|
||||
name:"connectivity",
|
||||
value:"REACHABLE",
|
||||
scale:"",
|
||||
timestampOfSample:0,
|
||||
uncertaintyInMilliseconds:10
|
||||
},
|
||||
{
|
||||
name:"turnOnState",
|
||||
value:powerstate==1?"ON":"OFF",
|
||||
scale:"",
|
||||
timestampOfSample:0,
|
||||
uncertaintyInMilliseconds:10,
|
||||
legalValue:"(ON, OFF)"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
url:"",//不指定直接作为响应返回
|
||||
header:{
|
||||
contentType:"application/json"
|
||||
},
|
||||
content:JSON.stringify(content)
|
||||
}
|
||||
}else if(namespace=="DuerOS.ConnectedHome.Control"){
|
||||
//设备控制
|
||||
var appliance=duPayload.appliance;
|
||||
var deviceId=appliance.applianceId;
|
||||
var confirmName="UnsupportedOperationError";
|
||||
var rst={status:500};
|
||||
|
||||
//开关
|
||||
if(requestName=="TurnOnRequest"){
|
||||
//开
|
||||
confirmName="TurnOnConfirmation";
|
||||
rst=apiTool.setProperties(token,deviceId,{powerstate:1});
|
||||
}else if(requestName=="TurnOffRequest"){
|
||||
//关
|
||||
confirmName="TurnOffConfirmation";
|
||||
rst=apiTool.setProperties(token,deviceId,{powerstate:0});
|
||||
}
|
||||
|
||||
if(rst.status!=200){
|
||||
confirmName="UnsupportedOperationError";
|
||||
apiTool.log("device control failed:"+JSON.stringify(rst));
|
||||
}
|
||||
|
||||
var content={
|
||||
header: {
|
||||
namespace: "DuerOS.ConnectedHome.Control",
|
||||
name: confirmName,
|
||||
messageId: messageId,
|
||||
payloadVersion: "1"
|
||||
},
|
||||
payload: {
|
||||
"attributes": []
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
url:"",
|
||||
header:{
|
||||
contentType:"application/json"
|
||||
},
|
||||
content:JSON.stringify(content)
|
||||
}
|
||||
}else if(namespace=="DuerOS.ConnectedHome.Query"){
|
||||
//属性查询
|
||||
if(requestName=="ReportStateRequest"){
|
||||
var appliance=duPayload.appliance;
|
||||
var deviceId=appliance.applianceId;
|
||||
var property=appliance.attributeName;
|
||||
var propertyVal="";
|
||||
var success=false;
|
||||
if(property=="turnOnState"){
|
||||
//开关状态查询
|
||||
var rst= apiTool.getSpaceDeviceDetail(token,deviceId);
|
||||
if(rst && rst.status==200 && rst.data.property){
|
||||
propertyVal=rst.data.property.powerstate==1?"ON":"OFF";
|
||||
success=true;
|
||||
}
|
||||
}
|
||||
var content=success?{
|
||||
"header": {
|
||||
"namespace": "DuerOS.ConnectedHome.Query",
|
||||
"name": "ReportStateResponse",
|
||||
"messageId": new Date().getTime()+"",
|
||||
"payloadVersion": "1"
|
||||
},
|
||||
"payload": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": property,
|
||||
"value": propertyVal,
|
||||
"scale": "",
|
||||
"timestampOfSample": new Date().getTime()/1000,
|
||||
"uncertaintyInMilliseconds": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}:{};
|
||||
|
||||
return {
|
||||
url:"",
|
||||
header:{
|
||||
contentType:"application/json"
|
||||
},
|
||||
content:JSON.stringify(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
url:"",//不指定直接作为响应返回
|
||||
header:{
|
||||
contentType:"application/json"
|
||||
},
|
||||
content:""
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,302 @@
|
|||
!function(n){"use strict";function d(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function f(n,t,r,e,o,u){return d((u=d(d(t,n),d(e,u)))<<o|u>>>32-o,r)}function l(n,t,r,e,o,u,c){return f(t&r|~t&e,n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t&e|r&~e,n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function c(n,t){var r,e,o,u;n[t>>5]|=128<<t%32,n[14+(t+64>>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h<n.length;h+=16)c=l(r=c,e=f,o=i,u=a,n[h],7,-680876936),a=l(a,c,f,i,n[h+1],12,-389564586),i=l(i,a,c,f,n[h+2],17,606105819),f=l(f,i,a,c,n[h+3],22,-1044525330),c=l(c,f,i,a,n[h+4],7,-176418897),a=l(a,c,f,i,n[h+5],12,1200080426),i=l(i,a,c,f,n[h+6],17,-1473231341),f=l(f,i,a,c,n[h+7],22,-45705983),c=l(c,f,i,a,n[h+8],7,1770035416),a=l(a,c,f,i,n[h+9],12,-1958414417),i=l(i,a,c,f,n[h+10],17,-42063),f=l(f,i,a,c,n[h+11],22,-1990404162),c=l(c,f,i,a,n[h+12],7,1804603682),a=l(a,c,f,i,n[h+13],12,-40341101),i=l(i,a,c,f,n[h+14],17,-1502002290),c=g(c,f=l(f,i,a,c,n[h+15],22,1236535329),i,a,n[h+1],5,-165796510),a=g(a,c,f,i,n[h+6],9,-1069501632),i=g(i,a,c,f,n[h+11],14,643717713),f=g(f,i,a,c,n[h],20,-373897302),c=g(c,f,i,a,n[h+5],5,-701558691),a=g(a,c,f,i,n[h+10],9,38016083),i=g(i,a,c,f,n[h+15],14,-660478335),f=g(f,i,a,c,n[h+4],20,-405537848),c=g(c,f,i,a,n[h+9],5,568446438),a=g(a,c,f,i,n[h+14],9,-1019803690),i=g(i,a,c,f,n[h+3],14,-187363961),f=g(f,i,a,c,n[h+8],20,1163531501),c=g(c,f,i,a,n[h+13],5,-1444681467),a=g(a,c,f,i,n[h+2],9,-51403784),i=g(i,a,c,f,n[h+7],14,1735328473),c=v(c,f=g(f,i,a,c,n[h+12],20,-1926607734),i,a,n[h+5],4,-378558),a=v(a,c,f,i,n[h+8],11,-2022574463),i=v(i,a,c,f,n[h+11],16,1839030562),f=v(f,i,a,c,n[h+14],23,-35309556),c=v(c,f,i,a,n[h+1],4,-1530992060),a=v(a,c,f,i,n[h+4],11,1272893353),i=v(i,a,c,f,n[h+7],16,-155497632),f=v(f,i,a,c,n[h+10],23,-1094730640),c=v(c,f,i,a,n[h+13],4,681279174),a=v(a,c,f,i,n[h],11,-358537222),i=v(i,a,c,f,n[h+3],16,-722521979),f=v(f,i,a,c,n[h+6],23,76029189),c=v(c,f,i,a,n[h+9],4,-640364487),a=v(a,c,f,i,n[h+12],11,-421815835),i=v(i,a,c,f,n[h+15],16,530742520),c=m(c,f=v(f,i,a,c,n[h+2],23,-995338651),i,a,n[h],6,-198630844),a=m(a,c,f,i,n[h+7],10,1126891415),i=m(i,a,c,f,n[h+14],15,-1416354905),f=m(f,i,a,c,n[h+5],21,-57434055),c=m(c,f,i,a,n[h+12],6,1700485571),a=m(a,c,f,i,n[h+3],10,-1894986606),i=m(i,a,c,f,n[h+10],15,-1051523),f=m(f,i,a,c,n[h+1],21,-2054922799),c=m(c,f,i,a,n[h+8],6,1873313359),a=m(a,c,f,i,n[h+15],10,-30611744),i=m(i,a,c,f,n[h+6],15,-1560198380),f=m(f,i,a,c,n[h+13],21,1309151649),c=m(c,f,i,a,n[h+4],6,-145523070),a=m(a,c,f,i,n[h+11],10,-1120210379),i=m(i,a,c,f,n[h+2],15,718787259),f=m(f,i,a,c,n[h+9],21,-343485551),c=d(c,r),f=d(f,e),i=d(i,o),a=d(a,u);return[c,f,i,a]}function i(n){for(var t="",r=32*n.length,e=0;e<r;e+=8)t+=String.fromCharCode(n[e>>5]>>>e%32&255);return t}function a(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e<t.length;e+=1)t[e]=0;for(var r=8*n.length,e=0;e<r;e+=8)t[e>>5]|=(255&n.charCodeAt(e/8))<<e%32;return t}function e(n){for(var t,r="0123456789abcdef",e="",o=0;o<n.length;o+=1)t=n.charCodeAt(o),e+=r.charAt(t>>>4&15)+r.charAt(15&t);return e}function r(n){return unescape(encodeURIComponent(n))}function o(n){return i(c(a(n=r(n)),8*n.length))}function u(n,t){return function(n,t){var r,e=a(n),o=[],u=[];for(o[15]=u[15]=void 0,16<e.length&&(e=c(e,8*n.length)),r=0;r<16;r+=1)o[r]=909522486^e[r],u[r]=1549556828^e[r];return t=c(o.concat(a(t)),512+8*t.length),i(c(u.concat(t),640))}(r(n),r(t))}function t(n,t,r){return t?r?u(t,n):e(u(t,n)):r?o(n):e(o(n))}"function"==typeof define&&define.amd?define(function(){return t}):"object"==typeof module&&module.exports?module.exports=t:n.md5=t}(this);
|
||||
var md5=this.md5;
|
||||
|
||||
function isServerId(clientId){
|
||||
return JSON.parse(component.getCompMqttClientIdList()).indexOf(clientId) > -1
|
||||
}
|
||||
|
||||
function getPkDn(clientId){
|
||||
var arr=clientId.split("_");
|
||||
return {
|
||||
pk:arr[0],
|
||||
dn:arr[1]
|
||||
};
|
||||
}
|
||||
|
||||
function auth(head,type,payload){
|
||||
if(isServerId(payload.clientid)){
|
||||
return {
|
||||
type:"serverAuth",
|
||||
data:{
|
||||
productKey:"pd",
|
||||
deviceName:"dn",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
var arr= payload.clientid.split("_");
|
||||
if(arr.length<3){
|
||||
throw new Error("incorrect clientid:" + payload.clientid);
|
||||
}
|
||||
|
||||
var pk=arr[0];
|
||||
var dn=arr[1];
|
||||
var model=arr[2];
|
||||
var pwd=md5("xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU"+payload.clientid);
|
||||
if(pwd!=payload.password){
|
||||
throw new Error("incorrect password:" + pwd);
|
||||
}
|
||||
return {
|
||||
type:"register",
|
||||
data:{
|
||||
productKey:pk,
|
||||
deviceName:dn,
|
||||
model:model
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function acl(head,type,payload){
|
||||
var _topic = payload.topic;
|
||||
|
||||
if(isServerId(payload.clientid)){
|
||||
return {
|
||||
type: "acl",
|
||||
data:{
|
||||
productKey:"pd",
|
||||
deviceName:"dn",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (/^\/sys\/.+\/.+\/c\/#/i.test(_topic)) {
|
||||
return subscribe(head,type,payload);
|
||||
}
|
||||
if (/^\/sys\/.+\/.+\/s\/.*/i.test(_topic)) {
|
||||
return subscribe(head,type,payload);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function register(head,type,payload){
|
||||
var auth= payload;
|
||||
var arr= auth.clientid.split("_");
|
||||
if(arr.length<3){
|
||||
throw new Error("incorrect clientid:" + auth.clientid);
|
||||
}
|
||||
|
||||
var pk=arr[0];
|
||||
var dn=arr[1];
|
||||
var model=arr[2];
|
||||
var pwd=md5("xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU"+auth.clientid);
|
||||
if(pwd!=auth.password){
|
||||
throw new Error("incorrect password:" + pwd);
|
||||
}
|
||||
return {
|
||||
type:"register",
|
||||
data:{
|
||||
productKey:pk,
|
||||
deviceName:dn,
|
||||
model:model
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function subRegister(topic,parent, payload){
|
||||
if(!topic){
|
||||
throw new Error("topic is blank")
|
||||
}
|
||||
|
||||
|
||||
var params= payload.params;
|
||||
|
||||
var reply=
|
||||
{
|
||||
productKey: parent.productKey,
|
||||
deviceName: parent.deviceName,
|
||||
mid: "0",
|
||||
content:{
|
||||
topic: topic.replace("/s/","/c/")+"_reply",
|
||||
payload: JSON.stringify({
|
||||
id: payload.id,
|
||||
code: 0,
|
||||
data: {
|
||||
"productKey":params.productKey,
|
||||
"deviceName":params.deviceName
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
type:"register",
|
||||
data:{
|
||||
productKey:parent.productKey,
|
||||
deviceName:parent.deviceName,
|
||||
subDevices:[{
|
||||
productKey:params.productKey,
|
||||
deviceName:params.deviceName,
|
||||
model:params.model
|
||||
}]
|
||||
},
|
||||
action:{
|
||||
type:"ack",
|
||||
content:JSON.stringify(reply)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function disconnect(head,type,payload){
|
||||
var clientId = payload.clientid
|
||||
var device=getPkDn(clientId);
|
||||
return {
|
||||
type:"state",
|
||||
data:{
|
||||
productKey:device.pk,
|
||||
deviceName:device.dn,
|
||||
state:"offline"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function connect(head,type,payload) {
|
||||
var clientId = payload.clientid
|
||||
var device = getPkDn(clientId);
|
||||
return {
|
||||
type: "state",
|
||||
data: {
|
||||
productKey: device.pk,
|
||||
deviceName: device.dn,
|
||||
state: "online"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function unsubscribe(head,type,payload){
|
||||
var topic = payload.topic;
|
||||
|
||||
if(isServerId(payload.clientid)){
|
||||
return {
|
||||
type: "acl",
|
||||
data:{
|
||||
productKey:"pd",
|
||||
deviceName:"dn",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var arr= topic.split('/');
|
||||
if(arr.length<6){
|
||||
throw new Error("incorrect topic: "+topic)
|
||||
}
|
||||
|
||||
var pk=arr[2];
|
||||
var dn=arr[3];
|
||||
|
||||
return {
|
||||
type:"state",
|
||||
data:{
|
||||
productKey: pk,
|
||||
deviceName: dn,
|
||||
state:"offline"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe(head,type,payload){
|
||||
var topic = payload.topic;
|
||||
|
||||
if(isServerId(payload.clientid)){
|
||||
return {
|
||||
type: "acl",
|
||||
data:{
|
||||
productKey:"pd",
|
||||
deviceName:"dn",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var arr= topic.split('/');
|
||||
if(arr.length<6){
|
||||
throw new Error("incorrect topic: "+topic)
|
||||
}
|
||||
var pk=arr[2];
|
||||
var dn=arr[3];
|
||||
|
||||
return {
|
||||
type: "state",
|
||||
data: {
|
||||
productKey: pk,
|
||||
deviceName: dn,
|
||||
state: "online"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var messageHandler = {
|
||||
"/sys/client/connected":connect,
|
||||
"/sys/client/disconnected":disconnect,
|
||||
"/mqtt/auth":auth,
|
||||
"/mqtt/acl":acl,
|
||||
"/sys/session/subscribed":subscribe,
|
||||
"/sys/session/unsubscribed":unsubscribe
|
||||
}
|
||||
|
||||
//必须提供onReceive方法
|
||||
this.onReceive=function(head,type,payload){
|
||||
payload=JSON.parse(payload);
|
||||
|
||||
print("======================================================================= ");
|
||||
print("【message from】: " + (isServerId(payload.clientid)?"Server":"Device") );
|
||||
print("onReceive head: "+JSON.stringify(head));
|
||||
print("onReceive type: "+JSON.stringify(type));
|
||||
print("onReceive payload: "+ JSON.stringify(payload));
|
||||
//print("onReceive compMqttClientIdList: "+ component.getCompMqttClientIdList());
|
||||
|
||||
var result = {};
|
||||
var topic = head.topic;
|
||||
if(!topic) {
|
||||
|
||||
print("【result】: " + JSON.stringify(result));
|
||||
print("======================================================================= ");
|
||||
return result;
|
||||
}
|
||||
|
||||
var fun = messageHandler[topic];
|
||||
|
||||
|
||||
|
||||
if(fun){
|
||||
result = fun(head,type,payload)
|
||||
}
|
||||
else{
|
||||
var arr= topic.split('/');
|
||||
if(arr.length<6){
|
||||
throw new Error("incorrect topic: "+topic)
|
||||
}
|
||||
var pk=arr[2];
|
||||
var dn=arr[3];
|
||||
|
||||
//子设备注册
|
||||
if(topic.endsWith('/register')){
|
||||
result = subRegister(topic,{productKey:pk,deviceName:dn}, payload);
|
||||
}
|
||||
else {
|
||||
//数据上报
|
||||
result = {
|
||||
type: "report",
|
||||
data: {
|
||||
productKey: pk,
|
||||
deviceName: dn,
|
||||
mid: payload.id,
|
||||
content: {
|
||||
topic: topic,
|
||||
payload: payload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
print("【result】: " + JSON.stringify(result));
|
||||
print("======================================================================= ");
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
this.onRegistered=function(regInfo,result){
|
||||
}
|
Binary file not shown.
|
@ -71,7 +71,7 @@ function subRegister(topic,parent,payload){
|
|||
content:{
|
||||
topic:topic.replace("/s/","/c/")+"_reply",
|
||||
payload:JSON.stringify({
|
||||
id:payload.id,
|
||||
id:"0",
|
||||
code:0,
|
||||
data:{
|
||||
"productKey":params.productKey,
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,74 @@
|
|||
var pidPkMap={
|
||||
"H5Z31yKBmy":"3ptfx2dRescPAwTn",
|
||||
"xOCy76jn6k":"jzC6eQGRse6hDZPB"
|
||||
}
|
||||
|
||||
this.onReceive=function(method,path,header,params,body){
|
||||
var type=header["Content-Type"];
|
||||
if(type=="application/json"){
|
||||
var msg=JSON.parse(body.msg);
|
||||
var productId=msg.productId;
|
||||
var deviceName=msg.deviceName;
|
||||
var messageType=msg.messageType;
|
||||
var data=msg.data;
|
||||
var pk=pidPkMap[productId];
|
||||
if(!pk){
|
||||
return {
|
||||
url:"",
|
||||
header:{
|
||||
contentType:"application/json"
|
||||
},
|
||||
content:"error"
|
||||
}
|
||||
}
|
||||
|
||||
if(messageType=="lifeCycle"){
|
||||
//登录、登出
|
||||
var online=data.status=="online";
|
||||
deviceBehaviour.deviceStateChange(pk,deviceName,online);
|
||||
}else if(messageType=="notify"){
|
||||
//设备消息
|
||||
//消息类型
|
||||
var notifyType=msg.notifyType;
|
||||
if(notifyType=="property"){
|
||||
//属性上报
|
||||
var propertyData={};
|
||||
for(var p in data.params){
|
||||
propertyData[p]=data.params[p].value;
|
||||
}
|
||||
deviceBehaviour.reportMessage(JSON.stringify({
|
||||
mid:data.id,
|
||||
productKey:pk,
|
||||
deviceName:deviceName,
|
||||
type:"property",
|
||||
identifier:"report",
|
||||
data:propertyData
|
||||
}));
|
||||
}else if(notifyType=="event"){
|
||||
//事件上报
|
||||
var identifier="";
|
||||
var paramData={};
|
||||
for(var p in data.params){
|
||||
identifier=p;
|
||||
paramData=data.params[p];
|
||||
}
|
||||
|
||||
deviceBehaviour.reportMessage(JSON.stringify({
|
||||
mid:data.id,
|
||||
productKey:pk,
|
||||
deviceName:deviceName,
|
||||
type:"event",
|
||||
identifier:identifier,
|
||||
data:paramData.value
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
url:"",
|
||||
header:{
|
||||
contentType:"application/json"
|
||||
},
|
||||
content:JSON.stringify(params.msg)
|
||||
}
|
||||
};
|
Binary file not shown.
|
@ -5,10 +5,10 @@
|
|||
"name": "移动Onenet Studio接入",
|
||||
"type": "biz",
|
||||
"protocol": "http",
|
||||
"jarFile": "http-biz-component-0.1.0-SNAPSHOT.jar",
|
||||
"jarFile": "iot-http-biz-component-0.3.2-SNAPSHOT.jar",
|
||||
"config": "{\"port\":\"8086\"}",
|
||||
"converter": "6260396d67aced2696184053",
|
||||
"state": "running",
|
||||
"state": "stop",
|
||||
"createAt": 1652238780184
|
||||
},
|
||||
{
|
||||
|
@ -17,34 +17,22 @@
|
|||
"name": "MQTT标准协议组件",
|
||||
"type": "device",
|
||||
"protocol": "mqtt",
|
||||
"jarFile": "iot-mqtt-component-0.3.1-SNAPSHOT.jar",
|
||||
"jarFile": "iot-mqtt-component-0.3.2-SNAPSHOT.jar",
|
||||
"config": "{\"port\":1883,\"ssl\":false,\"type\":\"server\"}",
|
||||
"converter": "6260396d67aced2696184053",
|
||||
"state": "running",
|
||||
"state": "stop",
|
||||
"createAt": 1650473458084
|
||||
},
|
||||
{
|
||||
"id": "cd8253c1-b489-434c-845d-d18c7b70dcea",
|
||||
"uid": "fa1c5eaa-de6e-48b6-805e-8f091c7bb831",
|
||||
"name": "电信NB协议接入组件",
|
||||
"type": "device",
|
||||
"protocol": "http",
|
||||
"jarFile": "ctwing-component-0.2.1-SNAPSHOT.jar",
|
||||
"config": "{\"port\":\"8087\"}",
|
||||
"converter": "62995ba4dbf51a5ec41d5f7b",
|
||||
"state": "stopped",
|
||||
"createAt": 1654235056032
|
||||
},
|
||||
{
|
||||
"id": "6c095554-35e7-4e9d-a8d2-bb919e9479f4",
|
||||
"uid": "fa1c5eaa-de6e-48b6-805e-8f091c7bb831",
|
||||
"name": "EMQX标准协议组件",
|
||||
"type": "device",
|
||||
"protocol": "mqtt",
|
||||
"jarFile": "emqx-component-0.2.1-SNAPSHOT.jar",
|
||||
"jarFile": "iot-emqx-component-0.3.2-SNAPSHOT.jar",
|
||||
"config": "{\"port\":\"1884\",\"ssl\":false,\"type\":\"client\",\"subscribeTopics\":[\"/sys/+/+/s/#\",\"/sys/client/connected\",\"/sys/client/disconnected\",\"/sys/session/subscribed\",\"/sys/session/unsubscribed\"],\"authPort\":\"8088\",\"broker\":\"127.0.0.1\",\"clientId\":\"test\",\"username\":\"test\",\"password\":\"123\"}",
|
||||
"converter": "6260396d67aced2696184053",
|
||||
"state": "running",
|
||||
"state": "stop",
|
||||
"createAt": 1653180468724
|
||||
},
|
||||
{
|
||||
|
@ -53,10 +41,10 @@
|
|||
"name": "小度音箱接入组件",
|
||||
"type": "biz",
|
||||
"protocol": "http",
|
||||
"jarFile": "http-biz-component-0.1.0-SNAPSHOT.jar",
|
||||
"jarFile": "iot-http-biz-component-0.3.2-SNAPSHOT.jar",
|
||||
"config": "{\"port\":\"8084\"}",
|
||||
"converter": "",
|
||||
"state": "running",
|
||||
"state": "stop",
|
||||
"createAt": 1650685502665
|
||||
}
|
||||
]
|
|
@ -0,0 +1,52 @@
|
|||
version: '3'
|
||||
services:
|
||||
redis:
|
||||
image: redis:5.0.8
|
||||
container_name: iotkit-ce-redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
volumes:
|
||||
- "redis-volume:/data"
|
||||
command: redis-server --appendonly yes
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
elasticsearch:
|
||||
image: elasticsearch:7.12.0
|
||||
container_name: iotkit-ce-elasticsearch
|
||||
environment:
|
||||
ES_JAVA_OPTS: -Djava.net.preferIPv4Stack=true -Xms1g -Xmx1g
|
||||
transport.host: 0.0.0.0
|
||||
discovery.type: single-node
|
||||
bootstrap.memory_lock: "true"
|
||||
ports:
|
||||
- 9200:9200
|
||||
- 9300:9300
|
||||
volumes:
|
||||
- "elasticsearch-volume:/usr/share/elasticsearch/data"
|
||||
ui:
|
||||
image: uncleregan/iotkit-ui:0.3.4
|
||||
container_name: iotkit-ce-ui
|
||||
ports:
|
||||
- 80:80
|
||||
links:
|
||||
- iotkit:iotkit
|
||||
volumes:
|
||||
- "iotkit-volume:/usr/share/nginx/html/upload"
|
||||
iotkit:
|
||||
image: uncleregan/iotkit:0.3.4
|
||||
container_name: iotkit-ce
|
||||
restart: on-failure
|
||||
ports:
|
||||
- 8086:8086 # API端口
|
||||
- 1883-1890:1883-1890 # 预留
|
||||
- 8000-8010:8000-8010 # 预留
|
||||
links:
|
||||
- redis:redis
|
||||
- elasticsearch:elasticsearch
|
||||
depends_on:
|
||||
- elasticsearch
|
||||
- redis
|
||||
volumes:
|
||||
redis-volume:
|
||||
elasticsearch-volume:
|
||||
iotkit-volume:
|
Binary file not shown.
Binary file not shown.
|
@ -1,92 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>iot-components</artifactId>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<version>0.3.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>iot-ctwing-component</artifactId>
|
||||
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-proxy</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ctg.ag</groupId>
|
||||
<artifactId>ctg-ag-sdk-core</artifactId>
|
||||
<version>2.5.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ctg.ag</groupId>
|
||||
<artifactId>ag-sdk-biz-84356.tar.gz</artifactId>
|
||||
<version>20220603.182201-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>iot-component-base</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>io.vertx:vertx-web-proxy</include>
|
||||
<include>io.vertx:vertx-web</include>
|
||||
<include>io.vertx:vertx-bridge-common</include>
|
||||
<include>io.vertx:vertx-http-proxy</include>
|
||||
<include>io.vertx:vertx-core</include>
|
||||
<include>io.netty:netty-codec-http2</include>
|
||||
<include>com.ctg.ag:ctg-ag-sdk-core</include>
|
||||
<include>com.ctg.ag:ag-sdk-biz-84356.tar.gz</include>
|
||||
<include>org.apache.httpcomponents:httpasyncclient</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.comp.http;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CtwingConfig {
|
||||
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* ctwing推送消息加解密token
|
||||
*/
|
||||
private String encryptToken;
|
||||
|
||||
/**
|
||||
* ctwing应用的appKey
|
||||
*/
|
||||
private String appKey;
|
||||
|
||||
/**
|
||||
* ctwing应用的appSecret
|
||||
*/
|
||||
private String appSecret;
|
||||
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
package cc.iotkit.comp.http;
|
||||
|
||||
import cc.iotkit.common.exception.BizException;
|
||||
import cc.iotkit.common.utils.CodecUtil;
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import cc.iotkit.comp.AbstractDeviceComponent;
|
||||
import cc.iotkit.comp.CompConfig;
|
||||
import cc.iotkit.converter.DeviceMessage;
|
||||
import com.ctg.ag.sdk.biz.AepDeviceCommandClient;
|
||||
import com.ctg.ag.sdk.biz.aep_device_command.CreateCommandRequest;
|
||||
import com.ctg.ag.sdk.biz.aep_device_command.CreateCommandResponse;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.core.http.HttpServerRequest;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 电信天翼接入组件
|
||||
*/
|
||||
@Slf4j
|
||||
public class CtwingDeviceComponent extends AbstractDeviceComponent {
|
||||
|
||||
private final Vertx vertx = Vertx.vertx();
|
||||
|
||||
private CtwingConfig ctwingConfig;
|
||||
|
||||
private HttpServer backendServer;
|
||||
|
||||
private AepDeviceCommandClient commandClient;
|
||||
|
||||
@Override
|
||||
public void create(CompConfig config) {
|
||||
super.create(config);
|
||||
this.ctwingConfig = JsonUtil.parse(config.getOther(), CtwingConfig.class);
|
||||
commandClient = AepDeviceCommandClient.newClient()
|
||||
.appKey(ctwingConfig.getAppKey())
|
||||
.appSecret(ctwingConfig.getAppSecret())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
backendServer = vertx.createHttpServer();
|
||||
Router backendRouter = Router.router(vertx);
|
||||
|
||||
backendRouter.route().handler(BodyHandler.create())
|
||||
.handler(rc -> {
|
||||
try {
|
||||
Map<String, Object> httpHeader = ProtocolUtil.getData(rc.request().headers());
|
||||
log.info("request header:{}", JsonUtil.toJsonString(httpHeader));
|
||||
Map<String, List<Object>> httpParams = ProtocolUtil.getListData(rc.request().params());
|
||||
log.info("request params:{}", JsonUtil.toJsonString(httpParams));
|
||||
|
||||
HttpServerRequest httpRequest = rc.request();
|
||||
String contentType = httpRequest.headers().get("Content-Type");
|
||||
String requestBody = "";
|
||||
int responseCode = 500;
|
||||
if ("application/json".equals(contentType)) {
|
||||
requestBody = rc.getBody().toString();
|
||||
EncodedMessage msg = JsonUtil.parse(requestBody, EncodedMessage.class);
|
||||
String content = CodecUtil.aesDecrypt(ctwingConfig.getEncryptToken(), msg.getEnc_msg());
|
||||
log.info("decrypt msg:{}", content);
|
||||
getHandler().onReceive(httpHeader, "", content);
|
||||
responseCode = 200;
|
||||
}
|
||||
log.info("request body:{}", requestBody);
|
||||
|
||||
rc.response().setStatusCode(responseCode)
|
||||
.end();
|
||||
} catch (Throwable e) {
|
||||
log.error("handle request error", e);
|
||||
rc.response().setStatusCode(500).end();
|
||||
}
|
||||
});
|
||||
|
||||
backendServer.requestHandler(backendRouter)
|
||||
.listen(ctwingConfig.getPort(), (http) -> {
|
||||
if (http.succeeded()) {
|
||||
log.info("http server create succeed,port:{}", ctwingConfig.getPort());
|
||||
} else {
|
||||
log.error("http server create failed", http.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceMessage send(DeviceMessage message) {
|
||||
Object obj = message.getContent();
|
||||
if (!(obj instanceof Map)) {
|
||||
throw new BizException("message content is not Map");
|
||||
}
|
||||
SendContent msg = new SendContent();
|
||||
try {
|
||||
BeanUtils.populate(msg, (Map<String, ? extends Object>) obj);
|
||||
} catch (Throwable e) {
|
||||
throw new BizException("message content is incorrect");
|
||||
}
|
||||
|
||||
CreateCommandRequest request = new CreateCommandRequest();
|
||||
request.setParamMasterKey(msg.getMasterKey());
|
||||
request.setBody(("{\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"dataType\":2,\n" +
|
||||
" \"payload\":\"" + msg.getPayload() + "\"\n" +
|
||||
" },\n" +
|
||||
" \"deviceId\":\"" + message.getDeviceName() + "\",\n" +
|
||||
" \"operator\":\"none\",\n" +
|
||||
" \"productId\":" + msg.getProductId() + ",\n" +
|
||||
" \"ttl\":0,\n" +
|
||||
" \"level\":1\n" +
|
||||
"}").getBytes());
|
||||
CreateCommandResponse response;
|
||||
try {
|
||||
response = commandClient.CreateCommand(request);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("send cmd to ctwing error", e);
|
||||
}
|
||||
|
||||
String body = new String(response.getBody());
|
||||
log.info("send ctwing cmd result:{}", body);
|
||||
if (response.getStatusCode() != 200) {
|
||||
throw new RuntimeException("send cmd to ctwing error:" + body);
|
||||
}
|
||||
|
||||
CtwingCmdRsp cmdRsp = JsonUtil.parse(body, CtwingCmdRsp.class);
|
||||
if (cmdRsp.code != 0) {
|
||||
throw new RuntimeException("send cmd to ctwing failed:" + body);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
backendServer.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据编码成68H16H协议数据包,给js调用
|
||||
*/
|
||||
public String encode68H16H(String devId, String cardNo, Object[] values) {
|
||||
return ProtocolUtil.encode68H16H(devId, cardNo, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将68H16H协议的base64字符串消息解码为map数据,给js调用
|
||||
*/
|
||||
public Map<String, Object> decode68H16H(String base64Str) {
|
||||
return ProtocolUtil.decode68H16H(base64Str);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class EncodedMessage {
|
||||
private String msg_signature;
|
||||
private String enc_msg;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SendContent {
|
||||
private String masterKey;
|
||||
private String productId;
|
||||
private String payload;
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
public static class CtwingCmdRsp {
|
||||
private int code;
|
||||
protected String msg;
|
||||
protected CmdResult result;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class CmdResult {
|
||||
private String commandId;
|
||||
private String command;
|
||||
private String commandStatus;
|
||||
private int productId;
|
||||
private String deviceId;
|
||||
private String imei;
|
||||
private String createBy;
|
||||
private String createTime;
|
||||
private int ttl;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
package cc.iotkit.comp.http;
|
||||
|
||||
import cc.iotkit.common.utils.HexUtil;
|
||||
import io.vertx.core.MultiMap;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
public class ProtocolUtil {
|
||||
|
||||
/**
|
||||
* 将数据编码成68H16H协议数据包
|
||||
*/
|
||||
public static String encode68H16H(String devId, String cardNo, Object[] values) {
|
||||
//构建数据域
|
||||
ByteBuffer bufferData = ByteBuffer.allocate(7);
|
||||
//模拟数据..
|
||||
bufferData.put((byte) 1);
|
||||
bufferData.putShort((short) 4);
|
||||
bufferData.putInt(100);
|
||||
byte[] data = bufferData.array();
|
||||
|
||||
//起始符到卡号部分数据
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1 + 2 + 5 + data.length + 4 + 7 + 2);
|
||||
int len = 1 + 2 + 5 + data.length + 4 + 7 + 2;
|
||||
buffer.put((byte) len);
|
||||
buffer.put((byte) 0x68);
|
||||
buffer.putShort((short) 0);
|
||||
buffer.put(devId.getBytes());
|
||||
buffer.put(data);
|
||||
buffer.putInt(0);
|
||||
buffer.put(cardNo.getBytes());
|
||||
byte[] data1 = buffer.array();
|
||||
|
||||
//校验码
|
||||
int check = HexUtil.calcCrc16(data1, 0, data1.length);
|
||||
//完整数据包
|
||||
buffer = ByteBuffer.allocate(1 + data1.length + 2 + 1);
|
||||
buffer.put((byte) (data1.length + 2));//帧长度
|
||||
buffer.put(data1);//起始符到卡号部分数据
|
||||
buffer.putShort((short) check);//检验码
|
||||
buffer.put((byte) 0x16);
|
||||
return HexUtil.toHexString(buffer.array());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将68H16H协议的base64字符串消息解码为map数据
|
||||
*/
|
||||
public static Map<String, Object> decode68H16H(String base64Str) {
|
||||
byte[] bytes = Base64.getDecoder().decode(base64Str);
|
||||
|
||||
Map<String, Object> decodeData = new HashMap<>();
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.flip();
|
||||
byte len = buffer.get();//帧长度
|
||||
buffer.get();//帧起始符
|
||||
buffer.getShort();//预留2byte
|
||||
byte[] devId = new byte[5];//设备ID
|
||||
buffer.get(devId, 0, 5);
|
||||
String strDevId = new String(devId);
|
||||
decodeData.put("devId", strDevId);
|
||||
|
||||
//数据域长度=帧长度-起始符-预留-设备ID-系统用-卡号-校验码
|
||||
int dataLen = len - 1 - 2 - 5 - 4 - 7 - 2;
|
||||
//数据域
|
||||
byte[] data = new byte[dataLen];
|
||||
buffer.get(data, 0, dataLen);
|
||||
Object[] values = ProtocolUtil.getTlvValues(data);
|
||||
//模拟取1个值
|
||||
decodeData.put("flow", values[0]);
|
||||
|
||||
buffer.getInt();//系统用
|
||||
//卡号
|
||||
byte[] card = new byte[7];
|
||||
buffer.get(card, 0, card.length);
|
||||
String cardNo = new String(card);
|
||||
decodeData.put("cardNo", cardNo);
|
||||
|
||||
return decodeData;
|
||||
}
|
||||
|
||||
public static Object[] getTlvValues(byte[] data) {
|
||||
List<Object> result = new ArrayList<>();
|
||||
|
||||
ByteBuffer dataBuff = ByteBuffer.wrap(data);
|
||||
dataBuff.flip();
|
||||
//对数据域解码...
|
||||
while (dataBuff.hasRemaining()) {
|
||||
byte t = dataBuff.get();
|
||||
byte l = dataBuff.get();
|
||||
byte[] bytesV = new byte[l];
|
||||
dataBuff.get(bytesV, 0, bytesV.length);
|
||||
if (t == 0) {
|
||||
//int
|
||||
result.add(HexUtil.bytesToInt(bytesV));
|
||||
}
|
||||
//..其它类型
|
||||
}
|
||||
return result.toArray();
|
||||
}
|
||||
|
||||
public static Map<String, List<Object>> getListData(MultiMap multiMap) {
|
||||
Map<String, List<Object>> listData = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : multiMap.entries()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
listData.putIfAbsent(key, new ArrayList<>());
|
||||
listData.get(key).add(value);
|
||||
}
|
||||
return listData;
|
||||
}
|
||||
|
||||
public static Map<String, Object> getData(MultiMap multiMap) {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : multiMap.entries()) {
|
||||
data.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
//引用api工具类
|
||||
var apiTool = Java.type("cc.iotkit.comp.biz.ApiTool");
|
||||
//api配置
|
||||
apiTool.config("http://localhost",8086,3000);
|
||||
|
||||
this.onReceive=function(method,path,header,params,body){
|
||||
//method:post、get、delete...
|
||||
//path:请求路径
|
||||
//header:http请求头数据,结构:{xx:xx,yy:yy}
|
||||
//params:请求参数,结构:{xx:[...],yy:[...]}
|
||||
//body:请求体,当提交的数据为json格式时使用,结构:{xx:xx,yy:yy}
|
||||
apiTool.log("onReceive method:"+method);
|
||||
apiTool.log("onReceive path:"+path);
|
||||
apiTool.log("onReceive header:"+header);
|
||||
apiTool.log("onReceive params:"+params);
|
||||
apiTool.log("onReceive body:"+body);
|
||||
var duHeader=body.header;
|
||||
var namespace=duHeader.namespace;
|
||||
var requestName=duHeader.name;
|
||||
var messageId=duHeader.messageId;
|
||||
var duPayload=duHeader.payload;
|
||||
var token=duHeader.accessToken;
|
||||
|
||||
//设备发现
|
||||
if(namespace=="DuerOS.ConnectedHome.Discovery" && requestName=="DiscoverAppliancesRequest"){
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
url:"xx",//不指定直接作为响应返回
|
||||
header:{
|
||||
contentType:"xx"
|
||||
},
|
||||
content:"xx"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
cc.iotkit.comp.http.CtwingDeviceComponent
|
|
@ -3,7 +3,7 @@
|
|||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<id>standalone-package</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
<format>tar</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<dependencySets>
|
||||
|
|
|
@ -93,6 +93,12 @@
|
|||
<dependency>
|
||||
<groupId>it.ozimov</groupId>
|
||||
<artifactId>embedded-redis</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<groupId>org.slf4j</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
@ -22,6 +22,8 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
//System.setProperty("disabledEmbeddedEs","true");
|
||||
//System.setProperty("disabledEmbeddedRedis","true");
|
||||
if (EmbeddedElasticSearchConfig.embeddedEnable()) {
|
||||
EmbeddedElasticSearchConfig.startEmbeddedElasticSearch();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ spring:
|
|||
elasticsearch:
|
||||
rest:
|
||||
#使用内置es的配置
|
||||
#uris: http://elasticsearch:9200
|
||||
uris: http://127.0.0.1:9200
|
||||
username:
|
||||
password:
|
||||
|
@ -18,6 +19,7 @@ spring:
|
|||
|
||||
redis:
|
||||
#使用内置redis的配置
|
||||
#host: redis
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
database: 0
|
||||
|
@ -29,10 +31,10 @@ spring:
|
|||
|
||||
#图片存储用的是阿里云oss,如果需要上传产品图片才需要配置
|
||||
aliyun:
|
||||
bucketId: iotkit-img
|
||||
endpoint: oss-cn-shenzhen.aliyuncs.com
|
||||
accessKeyId: 填写阿里云accessKeyId
|
||||
accessKeySecret: 填写阿里云accessKeySecret
|
||||
bucketId:
|
||||
endpoint:
|
||||
accessKeyId:
|
||||
accessKeySecret:
|
||||
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
|
|
Loading…
Reference in New Issue