diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..b385ebf9 --- /dev/null +++ b/Dockerfile @@ -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"] \ No newline at end of file diff --git a/README.md b/README.md index 598a6e66..2f231f8f 100755 --- a/README.md +++ b/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 + + + #### 技术文档 @@ -63,11 +70,11 @@ https://ztktkv.yuque.com/books/share/b96f1fee-41d8-4da3-9e22-b73aeb1e29ed?# 《i 如果我的开源软件应用到您的商业项目中,请务必通知到我,因为得到用户的认可是支撑开源的动力。 -交流QQ群: 940575749 +交流QQ群: 940575749 微信群: - ![输入图片说明](doc/ma.png) +![输入图片说明](doc/ma.png) ### roadmap diff --git a/data/components/3ababc5e-15e9-45a7-8f38-2a6afd45c780/component.js b/data/components/3ababc5e-15e9-45a7-8f38-2a6afd45c780/component.js new file mode 100644 index 00000000..ca368171 --- /dev/null +++ b/data/components/3ababc5e-15e9-45a7-8f38-2a6afd45c780/component.js @@ -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:"" + } +} \ No newline at end of file diff --git a/data/components/3ababc5e-15e9-45a7-8f38-2a6afd45c780/iot-http-biz-component-0.3.2-SNAPSHOT.jar b/data/components/3ababc5e-15e9-45a7-8f38-2a6afd45c780/iot-http-biz-component-0.3.2-SNAPSHOT.jar new file mode 100644 index 00000000..f46a9ffa Binary files /dev/null and b/data/components/3ababc5e-15e9-45a7-8f38-2a6afd45c780/iot-http-biz-component-0.3.2-SNAPSHOT.jar differ diff --git a/data/components/6c095554-35e7-4e9d-a8d2-bb919e9479f4/component.js b/data/components/6c095554-35e7-4e9d-a8d2-bb919e9479f4/component.js new file mode 100644 index 00000000..3109fa5f --- /dev/null +++ b/data/components/6c095554-35e7-4e9d-a8d2-bb919e9479f4/component.js @@ -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)))<>>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<>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h>5]>>>e%32&255);return t}function a(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e>5]|=(255&n.charCodeAt(e/8))<>>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 -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){ +} \ No newline at end of file diff --git a/data/components/6c095554-35e7-4e9d-a8d2-bb919e9479f4/iot-emqx-component-0.3.2-SNAPSHOT.jar b/data/components/6c095554-35e7-4e9d-a8d2-bb919e9479f4/iot-emqx-component-0.3.2-SNAPSHOT.jar new file mode 100644 index 00000000..dc9a4378 Binary files /dev/null and b/data/components/6c095554-35e7-4e9d-a8d2-bb919e9479f4/iot-emqx-component-0.3.2-SNAPSHOT.jar differ diff --git a/data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/component.js b/data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/component.js index 986f1aeb..9ccd4cf9 100644 --- a/data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/component.js +++ b/data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/component.js @@ -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, diff --git a/data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/iot-mqtt-component-0.3.1-SNAPSHOT.jar b/data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/iot-mqtt-component-0.3.2-SNAPSHOT.jar similarity index 94% rename from data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/iot-mqtt-component-0.3.1-SNAPSHOT.jar rename to data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/iot-mqtt-component-0.3.2-SNAPSHOT.jar index 6dfec6da..88515ab6 100644 Binary files a/data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/iot-mqtt-component-0.3.1-SNAPSHOT.jar and b/data/components/eabb131d-8fd1-43a8-88d9-a198abfd3d42/iot-mqtt-component-0.3.2-SNAPSHOT.jar differ diff --git a/data/components/fee0e826-963f-4e53-a2cf-11e3e5f784ea/component.js b/data/components/fee0e826-963f-4e53-a2cf-11e3e5f784ea/component.js new file mode 100644 index 00000000..0e8c664f --- /dev/null +++ b/data/components/fee0e826-963f-4e53-a2cf-11e3e5f784ea/component.js @@ -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) + } +}; \ No newline at end of file diff --git a/data/components/fee0e826-963f-4e53-a2cf-11e3e5f784ea/iot-http-biz-component-0.3.2-SNAPSHOT.jar b/data/components/fee0e826-963f-4e53-a2cf-11e3e5f784ea/iot-http-biz-component-0.3.2-SNAPSHOT.jar new file mode 100644 index 00000000..f46a9ffa Binary files /dev/null and b/data/components/fee0e826-963f-4e53-a2cf-11e3e5f784ea/iot-http-biz-component-0.3.2-SNAPSHOT.jar differ diff --git a/data/init/protocolComponent.json b/data/init/protocolComponent.json index 941b6c6f..f4584ae7 100644 --- a/data/init/protocolComponent.json +++ b/data/init/protocolComponent.json @@ -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 } ] \ No newline at end of file diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml new file mode 100644 index 00000000..1bedb1dc --- /dev/null +++ b/docker-compose/docker-compose.yml @@ -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: \ No newline at end of file diff --git a/iot-components/iot-ctwing-component/lib/ag-sdk-biz-84356.tar.gz-20220603.182201-SNAPSHOT.jar b/iot-components/iot-ctwing-component/lib/ag-sdk-biz-84356.tar.gz-20220603.182201-SNAPSHOT.jar deleted file mode 100644 index 2648a2b3..00000000 Binary files a/iot-components/iot-ctwing-component/lib/ag-sdk-biz-84356.tar.gz-20220603.182201-SNAPSHOT.jar and /dev/null differ diff --git a/iot-components/iot-ctwing-component/lib/ctg-ag-sdk-core-2.5.0-20220512.061430-51.jar b/iot-components/iot-ctwing-component/lib/ctg-ag-sdk-core-2.5.0-20220512.061430-51.jar deleted file mode 100644 index 2c9585be..00000000 Binary files a/iot-components/iot-ctwing-component/lib/ctg-ag-sdk-core-2.5.0-20220512.061430-51.jar and /dev/null differ diff --git a/iot-components/iot-ctwing-component/pom.xml b/iot-components/iot-ctwing-component/pom.xml deleted file mode 100644 index e0f33f12..00000000 --- a/iot-components/iot-ctwing-component/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - iot-components - cc.iotkit - 0.3.2-SNAPSHOT - - 4.0.0 - - iot-ctwing-component - - - - 8 - 8 - - - - - - org.projectlombok - lombok - - - - io.vertx - vertx-web-proxy - - - - com.ctg.ag - ctg-ag-sdk-core - 2.5.0-SNAPSHOT - - - - com.ctg.ag - ag-sdk-biz-84356.tar.gz - 20220603.182201-SNAPSHOT - - - - cc.iotkit - iot-component-base - - - - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.2.4 - - - package - - shade - - - - - - - io.vertx:vertx-web-proxy - io.vertx:vertx-web - io.vertx:vertx-bridge-common - io.vertx:vertx-http-proxy - io.vertx:vertx-core - io.netty:netty-codec-http2 - com.ctg.ag:ctg-ag-sdk-core - com.ctg.ag:ag-sdk-biz-84356.tar.gz - org.apache.httpcomponents:httpasyncclient - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - - - \ No newline at end of file diff --git a/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/CtwingConfig.java b/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/CtwingConfig.java deleted file mode 100644 index aca06a73..00000000 --- a/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/CtwingConfig.java +++ /dev/null @@ -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; - -} diff --git a/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/CtwingDeviceComponent.java b/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/CtwingDeviceComponent.java deleted file mode 100644 index c0580da0..00000000 --- a/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/CtwingDeviceComponent.java +++ /dev/null @@ -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 httpHeader = ProtocolUtil.getData(rc.request().headers()); - log.info("request header:{}", JsonUtil.toJsonString(httpHeader)); - Map> 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) 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 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; - } - -} diff --git a/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/ProtocolUtil.java b/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/ProtocolUtil.java deleted file mode 100644 index e0490c98..00000000 --- a/iot-components/iot-ctwing-component/src/main/java/cc/iotkit/comp/http/ProtocolUtil.java +++ /dev/null @@ -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 decode68H16H(String base64Str) { - byte[] bytes = Base64.getDecoder().decode(base64Str); - - Map 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 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> getListData(MultiMap multiMap) { - Map> listData = new HashMap<>(); - for (Map.Entry 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 getData(MultiMap multiMap) { - Map data = new HashMap<>(); - for (Map.Entry entry : multiMap.entries()) { - data.put(entry.getKey(), entry.getValue()); - } - return data; - } -} diff --git a/iot-components/iot-ctwing-component/src/main/resources/component.js b/iot-components/iot-ctwing-component/src/main/resources/component.js deleted file mode 100644 index 62112b41..00000000 --- a/iot-components/iot-ctwing-component/src/main/resources/component.js +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/iot-components/iot-ctwing-component/src/main/resources/component.spi b/iot-components/iot-ctwing-component/src/main/resources/component.spi deleted file mode 100644 index 51335f33..00000000 --- a/iot-components/iot-ctwing-component/src/main/resources/component.spi +++ /dev/null @@ -1 +0,0 @@ -cc.iotkit.comp.http.CtwingDeviceComponent \ No newline at end of file diff --git a/iot-package/src/main/resources/assemblies/standalone-package.xml b/iot-package/src/main/resources/assemblies/standalone-package.xml index 6860e112..01ae2d7c 100644 --- a/iot-package/src/main/resources/assemblies/standalone-package.xml +++ b/iot-package/src/main/resources/assemblies/standalone-package.xml @@ -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"> standalone-package - zip + tar false diff --git a/iot-standalone/pom.xml b/iot-standalone/pom.xml index ecdf563f..829877cd 100644 --- a/iot-standalone/pom.xml +++ b/iot-standalone/pom.xml @@ -93,6 +93,12 @@ it.ozimov embedded-redis + + + slf4j-simple + org.slf4j + + diff --git a/iot-standalone/src/main/java/cc/iotkit/manager/Application.java b/iot-standalone/src/main/java/cc/iotkit/manager/Application.java index ebc926c4..496ff24d 100644 --- a/iot-standalone/src/main/java/cc/iotkit/manager/Application.java +++ b/iot-standalone/src/main/java/cc/iotkit/manager/Application.java @@ -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(); } diff --git a/iot-standalone/src/main/resources/application.yml b/iot-standalone/src/main/resources/application.yml index baf8c348..036887e1 100644 --- a/iot-standalone/src/main/resources/application.yml +++ b/iot-standalone/src/main/resources/application.yml @@ -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名称)