diff --git a/README.md b/README.md index f21b125c..5bbaed04 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ - EMQ管理: Mqtt客户端、监听器、消息主题、消息订阅、插件管理、规则引擎、资源 - 硬件 SDK: 支持WIFI和MQTT连接、物模型响应、实时监测、定时上报监测数据、AES加密、NTP时间等 - 物模型管理: 属性(设备状态和监测数据),功能(执行特定任务),事件(设备主动上报给云端) -- 其他(开发中):第三方登录,设备分享、设备告警、场景联动(进度50%),智能音箱、多租户、APP界面自定义(进度40%),时序数据库、分布式集群部署、Granfa监控(进度30%),视频流处理、桌面端模拟器/监控、安卓端模拟器/监控(进度20%) +- 其他(开发中):第三方登录,设备分享、设备告警、场景联动(进度50%); 智能音箱、多租户、APP界面自定义(进度40%); 时序数据库、分布式集群部署、Granfa监控(进度30%); 视频流处理、桌面端模拟器/监控、安卓端模拟器/监控(进度20%) ### 四、技术栈 @@ -74,7 +74,7 @@ * [权限管理系统ruoyi-vue](https://gitee.com/y_project/RuoYi-Vue) * [Mqtt消息服务器EMQX4.0](https://github.com/emqx/emqx) * [ESP8266 Core For Arduino](https://github.com/esp8266/Arduino) -* [uCharts高性能跨平台图标库](https://www.ucharts.cn) +* [uCharts高性能跨平台图表库](https://www.ucharts.cn) ##### Docker快速安装 * Mysql中创建wumei-smart数据库,[导入Sql脚本](https://gitee.com/kerwincui/wumei-smart/tree/master/springboot/sql) * 修改命令中的Mysql配置,并执行 @@ -104,8 +104,8 @@ kerwincui/wumei-smart:1.1 ##### 项目贡献者 -|[小驿物联](https://gitee.com/iot-xiaoyi) |[Guanshubiao](https://gitee.com/guanshubiao)|[CrazyDull](https://gitee.com/crazyDull) |[Kami0314](https://github.com/kami0314)| -|--|--|--|--| +|[小驿物联](https://gitee.com/iot-xiaoyi) |[Guanshubiao](https://gitee.com/guanshubiao)|[CrazyDull](https://gitee.com/crazyDull) |[Kami0314](https://github.com/kami0314)|[YBZX](https://github.com/YBZX) +|--|--|--|--|--| | [SXH](https://gitee.com/sixiaohu) | [Redamancy_zxp](https://gitee.com/redamancy-zxp) | [LEE](https://gitee.com/yueming188) | [LemonTree](https://gitee.com/fishhunterplus) | [Tang](https://gitee.com/mexiaotang) |--|--|--|--|--| diff --git a/app/README.md b/app/README.md index 3f7b7a30..b80f8980 100644 --- a/app/README.md +++ b/app/README.md @@ -9,7 +9,7 @@ #### 四、通过赞助、贡献代码、推广可以加入项目内部,里面包含移动端源码和更多相关教程,并且获得一年的免费更新。目前项目还在完善,教程暂无,赞助费暂定1500元。可以通过官网[http://wumei.live/](http://wumei.live/) 注册账号,联系作者加入项目内部。 -##### 项目开发交流群:【946029159】,作者QQ: 【164770707】 +##### 项目开发交流群:【946029159】,项目互助交流群:【1073236354】,作者QQ: 【164770707】
diff --git a/sdk/RaspberryPi/README.md b/sdk/RaspberryPi/README.md index e69de29b..a355e222 100644 --- a/sdk/RaspberryPi/README.md +++ b/sdk/RaspberryPi/README.md @@ -0,0 +1,45 @@ +## 硬件端树莓派SDK说明 + +#### 一、运行环境 +- Python 3.7.2 (其他python3的版本一般也可以) +- 开发板:树莓派4b(没有加入硬件相关代码,安装好python3环境,win下,linux下都能运行) +- 库 需要安装库 + +1. mqtt库 + + ``` + pip install paho-mqtt + ``` + +2. ase加密库 + + ``` + # 前面两个卸载命令是为了防止一些安装环境问题 + pip uninstall crypto + pip uninstall pycryptodome + pip install pycryptodome + ``` + + +3. 报错缺少xx库,命令 + + ``` + pip install xx + ``` + + +#### 二、运行程序 + +``` +python3 main_sdk.py + +# 备注:程序运行依赖aes.py文件,保证该文件和main_sdk.py在同一目录 +``` + + + +#### 三、开发参考资料: + +- [Eclipse Paho MQTT Python Client 使用手册](https://www.cooooder.com/archives/20210303) +- 更多参考资料,下载目录中的文本文件查看 + diff --git a/sdk/RaspberryPi/aes.py b/sdk/RaspberryPi/aes.py new file mode 100644 index 00000000..ae52cd0f --- /dev/null +++ b/sdk/RaspberryPi/aes.py @@ -0,0 +1,210 @@ +from Crypto.Cipher import AES +import base64 +import binascii + + +# 数据类 +class MData(): + def __init__(self, data = b"",characterSet='utf-8'): + # data肯定为bytes + self.data = data + self.characterSet = characterSet + + def saveData(self,FileName): + with open(FileName,'wb') as f: + f.write(self.data) + + def fromString(self,data): + self.data = data.encode(self.characterSet) + return self.data + + def fromBase64(self,data): + self.data = base64.b64decode(data.encode(self.characterSet)) + return self.data + + def fromHexStr(self,data): + self.data = binascii.a2b_hex(data) + return self.data + + def toString(self): + return self.data.decode(self.characterSet) + + def toBase64(self): + return base64.b64encode(self.data).decode() #decode()转成字符串形式,否则为字节型数据 + + def toHexStr(self): + return binascii.b2a_hex(self.data).decode() + + def toBytes(self): + return self.data + + def __str__(self): + try: + return self.toString() + except Exception: + return self.toBase64() + + +### 封装类 +class AEScryptor(): + def __init__(self,key,mode,iv = '',paddingMode= "NoPadding",characterSet ="utf-8"): + ''' + 构建一个AES对象 + key: 秘钥,字节型数据 + mode: 使用模式,只提供两种,AES.MODE_CBC, AES.MODE_ECB + iv: iv偏移量,字节型数据 + paddingMode: 填充模式,默认为NoPadding, 可选NoPadding,ZeroPadding,PKCS5Padding,PKCS7Padding + characterSet: 字符集编码 + ''' + self.key = key + self.mode = mode + self.iv = iv + self.characterSet = characterSet + self.paddingMode = paddingMode + self.data = "" + + def __ZeroPadding(self,data): + data += b'\x00' + while len(data) % 16 != 0: + data += b'\x00' + return data + + def __StripZeroPadding(self,data): + data = data[:-1] + while len(data) % 16 != 0: + data = data.rstrip(b'\x00') + if data[-1] != b"\x00": + break + return data + + def __PKCS5_7Padding(self,data): + needSize = 16-len(data) % 16 + if needSize == 0: + needSize = 16 + return data + needSize.to_bytes(1,'little')*needSize + + def __StripPKCS5_7Padding(self,data): + paddingSize = data[-1] + return data.rstrip(paddingSize.to_bytes(1,'little')) + + def __paddingData(self,data): + if self.paddingMode == "NoPadding": + if len(data) % 16 == 0: + return data + else: + return self.__ZeroPadding(data) + elif self.paddingMode == "ZeroPadding": + return self.__ZeroPadding(data) + elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding": + return self.__PKCS5_7Padding(data) + else: + print("不支持Padding") + + def __stripPaddingData(self,data): + if self.paddingMode == "NoPadding": + return self.__StripZeroPadding(data) + elif self.paddingMode == "ZeroPadding": + return self.__StripZeroPadding(data) + + elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding": + return self.__StripPKCS5_7Padding(data) + else: + print("不支持Padding") + + def setCharacterSet(self,characterSet): + ''' + 设置字符集编码 + characterSet: 字符集编码 + ''' + self.characterSet = characterSet + + def setPaddingMode(self,mode): + ''' + 设置填充模式 + mode: 可选NoPadding,ZeroPadding,PKCS5Padding,PKCS7Padding + ''' + self.paddingMode = mode + + def decryptFromBase64(self,entext): + ''' + 从base64编码字符串编码进行AES解密 + entext: 数据类型str + ''' + mData = MData(characterSet=self.characterSet) + self.data = mData.fromBase64(entext) + return self.__decrypt() + + def decryptFromHexStr(self,entext): + ''' + 从hexstr编码字符串编码进行AES解密 + entext: 数据类型str + ''' + mData = MData(characterSet=self.characterSet) + self.data = mData.fromHexStr(entext) + return self.__decrypt() + + def decryptFromString(self,entext): + ''' + 从字符串进行AES解密 + entext: 数据类型str + ''' + mData = MData(characterSet=self.characterSet) + self.data = mData.fromString(entext) + return self.__decrypt() + + def decryptFromBytes(self,entext): + ''' + 从二进制进行AES解密 + entext: 数据类型bytes + ''' + self.data = entext + return self.__decrypt() + + def encryptFromString(self,data): + ''' + 对字符串进行AES加密 + data: 待加密字符串,数据类型为str + ''' + self.data = data.encode(self.characterSet) + return self.__encrypt() + + def __encrypt(self): + if self.mode == AES.MODE_CBC: + aes = AES.new(self.key,self.mode,self.iv) + elif self.mode == AES.MODE_ECB: + aes = AES.new(self.key,self.mode) + else: + print("不支持这种模式") + return + + data = self.__paddingData(self.data) + enData = aes.encrypt(data) + return MData(enData) + + def __decrypt(self): + if self.mode == AES.MODE_CBC: + aes = AES.new(self.key,self.mode,self.iv) + elif self.mode == AES.MODE_ECB: + aes = AES.new(self.key,self.mode) + else: + print("不支持这种模式") + return + data = aes.decrypt(self.data) + # mData = MData(self.__stripPaddingData(data),characterSet=self.characterSet) + # return mData() + return MData(self.__stripPaddingData(data),characterSet=self.characterSet) + + +if __name__ == '__main__': + key = b"1234567812345678" + iv = b"0000000000000000" + aes = AEScryptor(key,AES.MODE_CBC,iv,paddingMode= "ZeroPadding",characterSet='utf-8') + + data = "好好学习" + rData = aes.encryptFromString(data) + print("密文:",rData.toBase64()) + rData = aes.decryptFromBase64(rData.toBase64()) + print("明文:",rData) +# ———————————————— +# 版权声明:本文为CSDN博主「Hello_wshuo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 +# 原文链接:https://blog.csdn.net/chouzhou9701/article/details/122019967 \ No newline at end of file diff --git a/sdk/RaspberryPi/main_sdk.py b/sdk/RaspberryPi/main_sdk.py new file mode 100644 index 00000000..f752cf19 --- /dev/null +++ b/sdk/RaspberryPi/main_sdk.py @@ -0,0 +1,335 @@ +# /*********************************************************** +# * author: xiaoY [物美智能 wumei-smart] +# * create: 2022-05-10 +# * email:qimint@outlook.com +# * source:https://github.com/kerwincui/wumei-smart +# * board:raspberry 4b +# ***********************************************************/ + +import time +import requests +import json +from aes import AEScryptor,AES +import paho.mqtt.client as mqtt +import random +import threading #导入线程模块,用作定时器 + +################################################################# +# 需要连接好外部网络 +################################################################# + +# 作为python的AES的iv,应该为16位,字节型数据 +wumei_iv = b"wumei-smart-open" + +# NTP地址(用于获取时间,可选的修改为自己部署项目的地址) +ntpServer = "http://120.24.218.158:8080/iot/tool/ntp?deviceSendTime=" + +# 设备信息配置 +deviceNum = "DW43CI6RM8GMG23H" +userId = "1" +productId = "4" +firmwareVersion = "1.0" +# Mqtt配置 +mqttHost = "120.24.218.158" + +mqttPort = 1883 +mqttUserName = "wumei-smart" +mqttPwd = "P261I5G3RY3MCIGG" +# 作为python的AES的key,应该为16位,字节型数据 +mqttSecret = b"K2IB784BM0O01GG6" + +monitorCount =5 #发布监测数据的最大次数 +# 使用esp8266单片机时,服务器传来的间隔单位为毫秒,本程序由于定时运行需要的是秒,将转化为秒,如需毫秒运行,自行更改程序 +monitorInterval =5 # 发布监测数据的间隔,默认5秒 + +g_rc=-1 # 连接成功标志位 + +global t2 #全局变量,管理定时监测 + + + + +# 订阅的主题 +prefix = "/" + productId + "/" + deviceNum +sOtaTopic = prefix + "/ota/get" +sNtpTopic = prefix + "/ntp/get" +sPropertyTopic = prefix + "/property/get" +sFunctionTopic = prefix + "/function/get" +sPropertyOnline = prefix + "/property-online/get" +sFunctionOnline = prefix + "/function-online/get" +sMonitorTopic = prefix + "/monitor/get" +# 发布的主题 +pInfoTopic = prefix + "/info/post" +pNtpTopic = prefix + "/ntp/post" +pPropertyTopic = prefix + "/property/post" +pFunctionTopic = prefix + "/function/post" +pMonitorTopic = prefix + "/monitor/post" +pEventTopic = prefix + "/event/post" + +# 初始化 +# 连接(客户端ID = 设备编号 & 产品ID) +clientId = deviceNum + "&" + productId +client=mqtt.Client(clientId) + +#加密 (AES-CBC-128-pkcs5padding) +def encrypt(plain_data,wumei_key,wumei_iv): + aes=AEScryptor(wumei_key,AES.MODE_CBC,wumei_iv,paddingMode="PKCS5Padding",characterSet='utf-8') + rData=aes.encryptFromString(plain_data) + printMsg("密码(已加密):"+rData.toBase64()) + return rData.toBase64() + +#回调函数。当尝试与MQTT broker 建立连接时,触发该函数。 +#client 是本次连接的客户端实例。 +#userdata 是用户的信息,一般为空。但如果有需要,也可以通过 user_data_set 函数设置。 +#flags 保存服务器响应标志的字典 +#rc 是响应码。 +# 0: 连接成功 +# 1: 连接失败-不正确的协议版本 +# 2: 连接失败-无效的客户端标识符 +# 3: 连接失败-服务器不可用 +# 4: 连接失败-错误的用户名或密码 +# 5: 连接失败-未授权 +# 6-255: 未定义. +#一般情况下,我们只需要关注rc响应码是否为0就可以了。 +def on_connect(client,userdata,flags,rc): + if rc==0: + printMsg("连接成功") + # 放在on_connect下可以保证重连重新订阅 + # 订阅(OTA、NTP、属性、功能、实时监测) + + client.subscribe(sOtaTopic, 1) + client.subscribe(sNtpTopic, 1) + client.subscribe(sPropertyTopic, 1) + client.subscribe(sFunctionTopic, 1) + client.subscribe(sPropertyOnline, 1) + client.subscribe(sFunctionOnline, 1) + client.subscribe(sMonitorTopic, 1) + + printMsg("订阅主题:" + sOtaTopic) + printMsg("订阅主题:" + sNtpTopic) + printMsg("订阅主题:" + sPropertyTopic) + printMsg("订阅主题:" + sFunctionTopic) + printMsg("订阅主题:" + sPropertyOnline) + printMsg("订阅主题:" + sFunctionOnline) + printMsg("订阅主题:" + sMonitorTopic) + # 发布设备信息 + publishInfo() + global g_rc + g_rc=0 + else: + printMsg("连接失败,rc="+str(rc)) + printMsg("3秒后重连...") + time.sleep(3) + connectMqtt() + +# 物模型-属性处理 +def processProperty(payload): + data=json.loads(payload) + for item in data: + # 匹配云端定义的属性(不包含属性中的监测数据) + id = item["id"] + value=item["value"] + printMsg(str(id)+":"+str(value)) + # 最后发布属性,服务端订阅存储(重要) + publishProperty(json.dumps(data)) + +# 物模型-功能处理 +def processFunction(payload): + data=json.loads(payload) + for item in data: + # 匹配云端定义的功能 + id = item["id"] + value=item["value"] + if(id=="switch"): + printMsg("开关 switch:"+ str(value)) + elif(id=="gear"): + printMsg("档位 gear:"+ str(value)) + elif(id=="light_color"): + printMsg("灯光颜色 light_color:"+ str(value)) + elif(id=="message"): + printMsg("屏显消息 message:"+ str(value)) + elif(id=="report_monitor"): + msg=randomPropertyData(); + printMsg("订阅到上报监测数据指令,上报数据:") + printMsg(msg) + publishProperty(msg) + # 最后发布属性,服务端订阅存储(重要) + publishProperty(json.dumps(data)) + +# 回调函数,在客户端订阅的主题上接收到消息时调用,“message”变量是一个MQTT消息描述所有消息特征 +def on_message(client,userdata,msg): + printMsg("接收数据:"+msg.topic+" "+str(msg.payload)) + if(msg.topic==sOtaTopic): + printMsg("订阅到设备升级指令...") + elif(msg.topic==sNtpTopic): + printMsg("订阅到NTP时间..."); + jsonData=json.loads(msg.payload) + deviceSendTime = jsonData["deviceSendTime"] + serverSendTime = jsonData["serverSendTime"] + serverRecvTime = jsonData["serverRecvTime"] + deviceRecvTime = round(time.time()*1000) + now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2 + printMsg("当前时间:"+str(round(now))) + elif(msg.topic==sPropertyTopic or msg.topic==sPropertyOnline): + printMsg("订阅到属性指令...") + processProperty(msg.payload) + elif(msg.topic==sFunctionTopic or msg.topic==sFunctionOnline): + printMsg("订阅到功能指令...") + processFunction(msg.payload) + elif(msg.topic==sMonitorTopic): + # python全局变量的使用 + global t2 + global monitorCount + global monitorInterval + printMsg("订阅到实时监测指令...") + jsonData=json.loads(msg.payload) + monitorCount = jsonData["count"] + monitorInterval = jsonData["interval"]/1000 + t2.cancel() + t2=threading.Timer(monitorInterval,timing_publishMonitor) + t2.start() + +# 1.发布设备信息 +def publishInfo(): + # rssi值 树莓派中暂时不处理wifi信号问题 + # 信号强度(信号极好4格[-55— 0],信号好3格[-70— -55],信号一般2格[-85— -70],信号差1格[-100— -85]) + # status值 (1-未激活,2-禁用,3-在线,4-离线) + doc={"rssi":1,"firmwareVersion":firmwareVersion,"status":3,"userId":userId} + # client.publish('raspberry/topic',payload=i,qos=0,retain=False) + jsonData=json.dumps(doc) + printMsg("发布设备信息:"+pInfoTopic+" "+jsonData) + client.publish(pInfoTopic,jsonData) + +# 2.发布时钟同步信,用于获取当前时间(可选) +def publishNtp(): + data={"deviceSendTime":round(time.time()*1000)} + jsonData=json.dumps(data) + printMsg("发布NTP信息"+jsonData) + client.publish(pNtpTopic,jsonData) + +# 3.发布属性 +# msg 接收格式json +def publishProperty(msg): + printMsg("发布属性:" + msg) + client.publish(pPropertyTopic, msg) + +# 4.发布功能 +def publishFunction( msg): + printMsg("发布功能:" + msg) + client.publish(pFunctionTopic, msg) + +# 5.发布事件 +def publishEvent(): + objTmeperature={"id":"height_temperature","value":40,"remark":"温度过高警告"} + objException={"id":"exception","value":"异常消息,消息内容XXXXXXXX","remark":"设备发生错误"} + data=[objTmeperature,objException] + jsonData=json.dumps(data) + printMsg("发布事件:"+jsonData) + client.publish(pEventTopic,jsonData) + +# 6.发布实时监测数据 +def publishMonitor(): + msg=randomPropertyData() + # 发布为实时监测数据,不会存储 + printMsg("发布实时监测数据:"+msg) + client.publish(pMonitorTopic,msg) + +# 随机生成监测值 +def randomPropertyData(): + # 匹配云端定义的监测数据,随机数代替监测结果 + # random.randint(0,10) #生成数据包括0,10 + # random.uniform(30,60)生成数据为浮点型 + objTmeperature={"id":"temperature","value":str(round(random.uniform(10,30),2)),"remark":""} + objHumidity={"id":"humidity","value":str(round(random.uniform(30,60),2)),"remark":""} + objCo2={"id":"co2","value":str(random.randint(400,1000)),"remark":""} + objBrightness={"id":"brightness","value":str(random.randint(1000,10000)),"remark":""} + printMsg("随机生成监测数据值:") + data=[objTmeperature,objHumidity,objCo2,objBrightness] + print(json.dumps(data)) + return json.dumps(data) + +#连接mqtt +def connectMqtt(): + printMsg("连接Mqtt服务器") + # 生成mqtt认证密码(密码 = mqtt密码 & 用户ID & 过期时间) + password = generationPwd() + encryptPassword=encrypt(password,mqttSecret,wumei_iv) + # 生成mqtt认证密码(密码 = mqtt密码 & 用户ID & 过期时间) + client.username_pw_set(mqttUserName,encryptPassword) + client.on_connect=on_connect + client.on_message=on_message + client.connect(mqttHost,mqttPort,10) + + + + +#打印提示信息 +def printMsg(msg): + print("[{}] {}".format(time.strftime("%Y-%m-%d %H:%M:%S"),msg)) +# 生成密码 +def generationPwd(): + try: + doc=json.loads(getTime()) + except: + printMsg("Json解析失败") + exit() + deviceSendTime = doc["deviceSendTime"] + serverSendTime = doc["serverSendTime"] + serverRecvTime = doc["serverRecvTime"] + deviceRecvTime = round(time.time()*1000) + now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2 + expireTime = int(now + 1 * 60 * 60 * 1000) + password = mqttPwd + "&" + userId + "&" + str(expireTime) + printMsg("密码(未加密):" + password) + return password +# HTTP获取时间 +def getTime(): + try: + r=requests.get(ntpServer+str(round(time.time()*1000))) + if(r.status_code>0): + if(r.status_code==200 or r.status_code==301): + printMsg("获取时间成功,data:"+r.text) + return r.text + else: + printMsg("获取时间失败,error:"+r.status_code) + except: + printMsg("连接Http失败") + + +def timing_publishProperty(): + printMsg("执行定时上报") + #发布事件 + publishEvent() + #发布时钟同步 + publishNtp() + # 发布属性(监测值) + msg=randomPropertyData() + publishProperty(msg) + t1=threading.Timer(60,timing_publishProperty) + t1.start() +def timing_publishMonitor(): + global monitorCount + monitorCount=monitorCount-1 + printMsg("执行监测") + publishMonitor() + if(monitorCount>0): + t2=threading.Timer(monitorInterval,timing_publishMonitor) + t2.start() + +if __name__ == '__main__': + connectMqtt() + client.loop_start() + printMsg("等待连接MQTT") + while(g_rc!=0): + print("-",end=" ") + time.sleep(1) + t1=threading.Timer(60,timing_publishProperty) + t1.setDaemon(True) #当主线程被关闭后,子线程也关闭 + t1.start() + t2=threading.Timer(monitorInterval,timing_publishMonitor) + t2.setDaemon(True) #当主线程被关闭后,子线程也关闭 + t2.start() + + while True: + time.sleep(10) #定时上报、检测上报都是线程执行,主线程可以做自己的任务 + diff --git a/sdk/RaspberryPi/更多参考教程.txt b/sdk/RaspberryPi/更多参考教程.txt new file mode 100644 index 00000000..8a5b5765 --- /dev/null +++ b/sdk/RaspberryPi/更多参考教程.txt @@ -0,0 +1,26 @@ +Eclipse Paho MQTT Python Client 使用手册 + https://www.cooooder.com/archives/20210303 + +Python 实现AES加密 + https://zhuanlan.zhihu.com/p/261694311 + +python实现AES加密解密 + https://blog.csdn.net/chouzhou9701/article/details/122019967 + +使用python time()方法 + http://www.py.cn/jishu/jichu/20424.html + +python 线程定时器Timer + https://zhuanlan.zhihu.com/p/91412537 + +浅谈Python的格式化输出 + https://www.jb51.net/article/225609.htm + +Python Request库入门 + https://www.jianshu.com/p/d78982126318 + +Python JSON + https://www.runoob.com/python/python-json.html + +Python random() 函数 + https://www.runoob.com/python/func-number-random.html \ No newline at end of file diff --git a/springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java b/springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java index 60155a3b..d1503d6d 100644 --- a/springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java +++ b/springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java @@ -1,21 +1,34 @@ package com.ruoyi.framework.config; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; +import java.util.*; +import javax.servlet.*; import javax.sql.DataSource; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; +import com.alibaba.druid.util.Utils; +import com.ruoyi.common.enums.DataSourceType; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.framework.config.properties.DruidProperties; +import com.ruoyi.framework.datasource.DynamicDataSource; import org.apache.ibatis.io.VFS; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.core.annotation.Order; import org.springframework.core.env.Environment; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; @@ -34,8 +47,8 @@ import com.ruoyi.common.utils.StringUtils; * @author ruoyi */ @Configuration -public class MyBatisConfig -{ +@MapperScan(basePackages = {"com.ruoyi.iot.mapper", "com.ruoyi.system.mapper", "com.ruoyi.quartz.mapper", "com.ruoyi.generator.mapper"}, sqlSessionTemplateRef = "mysqlSqlSessionTemplate") +public class MyBatisConfig { @Autowired private Environment env; @@ -119,10 +132,11 @@ public class MyBatisConfig @Bean(name = "mysqlSessionFactory") @Primary - public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception + public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception { - String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage"); - String mapperLocations = env.getProperty("mybatis.mapperLocations"); + String typeAliasesPackage = "com.ruoyi.**.domain";//env.getProperty("mybatis.typeAliasesPackage"); + String mapperLocations = "classpath:mapper/iot/*Mapper.xml,classpath:mapper/system/*Mapper.xml,classpath:mapper/quartz/*Mapper.xml"; +// String typeAliasesPackage = "com.ruoyi.**.domain"; String configLocation = env.getProperty("mybatis.configLocation"); typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage); VFS.addImplClass(SpringBootVFS.class); @@ -146,4 +160,5 @@ public class MyBatisConfig public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } + } \ No newline at end of file diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/controller/ToolController.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/controller/ToolController.java index c0004c76..13cc123f 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/controller/ToolController.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/controller/ToolController.java @@ -138,13 +138,13 @@ public class ToolController extends BaseController { // 设备端 String[] clientInfo = clientid.split("&"); if (clientInfo.length != 2) { - // 设备未加密认证 + // 设备简单认证 String deviceNum = clientInfo[0]; Device device = deviceService.selectShortDeviceBySerialNumber(deviceNum); if (device !=null && mqttConfig.getusername().equals(username) && mqttConfig.getpassword().equals(password)) { System.out.println("-----------认证成功,clientId:" + clientid + "---------------"); - ProductAuthorize authorize = new ProductAuthorize(null, device.getProductId(), device.getDeviceId(), device.getSerialNumber(), 1L, "admin"); - authorizeService.boundProductAuthorize(authorize); +// ProductAuthorize authorize = new ProductAuthorize(null, device.getProductId(), device.getDeviceId(), device.getSerialNumber(), 1L, "admin"); +// authorizeService.boundProductAuthorize(authorize); return ResponseEntity.ok().body("ok"); } return returnUnauthorized(clientid, username, password, "认证信息有误"); @@ -178,16 +178,16 @@ public class ToolController extends BaseController { // 设备状态验证 (1-未激活,2-禁用,3-在线,4-离线) if (model.getDeviceId() != null && model.getDeviceId() != 0 && model.getStatus() != 2) { System.out.println("-----------认证成功,clientId:" + clientid + "---------------"); - ProductAuthorize authorize = new ProductAuthorize(null, model.getProductId(), model.getDeviceId(), model.getSerialNumber(), 1L, "admin"); - authorizeService.boundProductAuthorize(authorize); +// ProductAuthorize authorize = new ProductAuthorize(null, model.getProductId(), model.getDeviceId(), model.getSerialNumber(), 1L, "admin"); +// authorizeService.boundProductAuthorize(authorize); return ResponseEntity.ok().body("ok"); } else { // 自动添加设备 int result = deviceService.insertDeviceAuto(deviceNum, userId, productId); if (result == 1) { System.out.println("-----------认证成功,clientId:" + clientid + "---------------"); - ProductAuthorize authorize = new ProductAuthorize(null, model.getProductId(), model.getDeviceId(), model.getSerialNumber(), 1L, "admin"); - authorizeService.boundProductAuthorize(authorize); +// ProductAuthorize authorize = new ProductAuthorize(null, model.getProductId(), model.getDeviceId(), model.getSerialNumber(), 1L, "admin"); +// authorizeService.boundProductAuthorize(authorize); return ResponseEntity.ok().body("ok"); } } diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/init/ApplicationStarted.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/init/ApplicationStarted.java new file mode 100644 index 00000000..e809d54e --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/init/ApplicationStarted.java @@ -0,0 +1,76 @@ +package com.ruoyi.iot.init; + + +//import com.ruoyi.mysql.config.TDengineConfig; + +//import com.ruoyi.iot.tdengine.config.TDengineConfig; +import com.alibaba.druid.pool.DruidDataSource; +import com.ruoyi.iot.tdengine.config.TDengineConfig; + import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.mapper.DeviceMapper; +import com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper; + import org.mybatis.spring.SqlSessionTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.util.Date; + +/** + * 类名: ApplicationStarted + * 描述: TODO + * 时间: 2022/5/18,0018 1:41 + * 开发人: wxy + */ +@Component +public class ApplicationStarted implements ApplicationRunner { + + private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationStarted.class); + + @Autowired + private TDengineConfig dengineConfig; + + @Autowired + private TDDeviceLogMapper deviceLogMapper; + + @Autowired + private DeviceMapper deviceMapper; + + @Override + public void run(ApplicationArguments args) { + deviceMapper.selectDeviceByDeviceId(0L); + System.out.println("初始化MySql链接成功"); + initTDengine(); + System.out.println("初始化TDengine链接成功"); + } + + /** + * @Method + * @Description 开始初始化加载系统参数,创建数据库和超级表 + * @Param null + * @return + * @date 2022/5/22,0022 14:27 + * @author wxy + * + */ + public void initTDengine() { + try { + String dbName = dengineConfig.getDbName(); + int db = deviceLogMapper.createDB(dbName); + deviceLogMapper.createSTable(dbName); + + System.out.println(db); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("ERROR"); + } + + } + +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/ILogService.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/ILogService.java new file mode 100644 index 00000000..829c962a --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/ILogService.java @@ -0,0 +1,25 @@ +package com.ruoyi.iot.log.service; + +import com.ruoyi.iot.domain.DeviceLog; + +import com.ruoyi.iot.model.MonitorModel; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +/** + * @package iot.iot.log + * 类名: LogService + * 描述: 设备日志记录接口 + * 时间: 2022/5/19,0019 18:04 + * 开发人: admin + */ +public interface ILogService { + + int saveDeviceLog(DeviceLog deviceLog); + + List selectDeviceLogList(DeviceLog deviceLog); + + List selectMonitorList(DeviceLog deviceLog); +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/factory/LogServiceFactory.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/factory/LogServiceFactory.java new file mode 100644 index 00000000..acd7be7f --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/factory/LogServiceFactory.java @@ -0,0 +1,74 @@ +package com.ruoyi.iot.log.service.factory; + +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.framework.config.MyBatisConfig; +import com.ruoyi.iot.log.service.impl.MySqlLogServiceImpl; +import com.ruoyi.iot.log.service.impl.TdengineLogServiceImpl; +import com.ruoyi.iot.model.MonitorModel; +import com.ruoyi.iot.tdengine.config.TDengineConfig; +import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.log.service.ILogService; +import com.ruoyi.iot.mapper.DeviceLogMapper; +import com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper; +import com.ruoyi.iot.util.SnowflakeIdWorker; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.lang.Nullable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 类名: DeviceLogServiceImpl + * 描述: TODO + * 时间: 2022/5/19,0019 18:09 + * 开发人: wxy + */ +@Component +public class LogServiceFactory { + + @Autowired + private ApplicationContext applicationContext; + + @Bean + public ILogService getLogService() { + //先获取TDengine的配置,检测TDengine是否已经配置 + if (containBean(TDengineConfig.class)) { + TDengineConfig tDengineConfig = applicationContext.getBean(TDengineConfig.class); + TDDeviceLogMapper tDDeviceLogMapper = applicationContext.getBean(TDDeviceLogMapper.class); + ILogService logService = new TdengineLogServiceImpl(tDengineConfig, tDDeviceLogMapper); + return logService; + } else if (containBean(MyBatisConfig.class)) { + //没有配置TDengine,那么使用MySQL的日志配置 + DeviceLogMapper deviceLogMapper = applicationContext.getBean( DeviceLogMapper.class); + ILogService logService = new MySqlLogServiceImpl(deviceLogMapper); + return logService; + } else { + return null; + } + } + + /** + * @Method containBean + * @Description 根据类判断是否有对应bean + * @Param 类 + * @return + * @date 2022/5/22,0022 14:12 + * @author wxy + * + */ + private boolean containBean(@Nullable Class T) { + String[] beans = applicationContext.getBeanNamesForType(T); + if (beans == null || beans.length == 0) { + return false; + } else { + return true; + } + } +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/impl/MySqlLogServiceImpl.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/impl/MySqlLogServiceImpl.java new file mode 100644 index 00000000..1ba1f610 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/impl/MySqlLogServiceImpl.java @@ -0,0 +1,38 @@ +package com.ruoyi.iot.log.service.impl; + +import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.log.service.ILogService; +import com.ruoyi.iot.mapper.DeviceLogMapper; +import com.ruoyi.iot.model.MonitorModel; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 类名: MySqlLogServiceImpl + * 描述: MySQL存储日志实现类 + * 时间: 2022/5/22,0022 13:37 + * 开发人: admin + */ +public class MySqlLogServiceImpl implements ILogService { + + private DeviceLogMapper deviceLogMapper; + + public MySqlLogServiceImpl(DeviceLogMapper _deviceLogMapper){ + this.deviceLogMapper=_deviceLogMapper; + } + @Override + public int saveDeviceLog(DeviceLog deviceLog) { + return deviceLogMapper.insertDeviceLog(deviceLog); + } + + @Override + public List selectDeviceLogList(DeviceLog deviceLog) { + return deviceLogMapper.selectDeviceLogList(deviceLog); + } + + @Override + public List selectMonitorList(DeviceLog deviceLog) { + return deviceLogMapper.selectMonitorList(deviceLog); + } +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/impl/TdengineLogServiceImpl.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/impl/TdengineLogServiceImpl.java new file mode 100644 index 00000000..58d381a5 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/log/service/impl/TdengineLogServiceImpl.java @@ -0,0 +1,57 @@ +package com.ruoyi.iot.log.service.impl; + +import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.log.service.ILogService; +import com.ruoyi.iot.model.MonitorModel; +import com.ruoyi.iot.tdengine.config.TDengineConfig; +import com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper; +import com.ruoyi.iot.util.SnowflakeIdWorker; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 类名: TdengineLogServiceImpl + * 描述: TDengine存储日志数据实现类 + * 时间: 2022/5/22,0022 13:38 + * 开发人: admin + */ +public class TdengineLogServiceImpl implements ILogService { + + private ApplicationContext applicationContext; + + private TDDeviceLogMapper tdDeviceLogMapper; + + private TDengineConfig tDengineConfig; + + private SnowflakeIdWorker snowflakeIdWorker; + + private String dbName; + + public TdengineLogServiceImpl(TDengineConfig _tDengineConfig,TDDeviceLogMapper _tdDeviceLogMapper) { + this.tdDeviceLogMapper = _tdDeviceLogMapper; + this.tDengineConfig = _tDengineConfig; + snowflakeIdWorker=new SnowflakeIdWorker(1); + this.dbName=_tDengineConfig.getDbName(); + } + + @Override + public int saveDeviceLog(DeviceLog deviceLog) { + long logId = snowflakeIdWorker.nextId(); + deviceLog.setLogId(logId); + return tdDeviceLogMapper.save(dbName,deviceLog); + } + + @Override + public List selectDeviceLogList(DeviceLog deviceLog) { + return tdDeviceLogMapper.selectDeviceLogList(dbName,deviceLog); + } + + @Override + public List selectMonitorList(DeviceLog deviceLog) { + return tdDeviceLogMapper.selectMonitorList(dbName,deviceLog); + } +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxClient.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxClient.java index 93735d24..5d965bf8 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxClient.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxClient.java @@ -79,7 +79,7 @@ public class EmqxClient { token.waitForCompletion(); }catch (Exception e){ logger.error("=====>>>>>mqtt连接失败 message={}",e.getMessage()); - throw new ServiceException("mqtt客户端连接错误"+e.getMessage()); +// e.printStackTrace(); } } } @@ -98,7 +98,7 @@ public class EmqxClient { logger.debug("====>>>mqtt客户端启动成功"); }catch (MqttException e){ logger.error("mqtt客户端连接错误 error={}",e.getMessage()); - throw new ServiceException("mqtt客户端连接错误"+e.getMessage()); +// e.printStackTrace(); } } } diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java index 0d2d1710..bd875259 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java @@ -3,13 +3,16 @@ package com.ruoyi.iot.mqtt; import com.alibaba.fastjson.JSON; import com.ruoyi.iot.domain.Device; import com.ruoyi.iot.domain.DeviceLog; -import com.ruoyi.iot.tdengine.service.ILogService; +import com.ruoyi.iot.log.service.ILogService; import com.ruoyi.iot.model.NtpModel; import com.ruoyi.iot.model.ThingsModels.IdentityAndName; +import com.ruoyi.iot.model.ThingsModels.ThingsModelValueItem; import com.ruoyi.iot.model.ThingsModels.ThingsModelValueRemarkItem; import com.ruoyi.iot.model.ThingsModels.ThingsModelValuesInput; +import com.ruoyi.iot.service.IDeviceLogService; import com.ruoyi.iot.service.IDeviceService; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; +import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.slf4j.Logger; diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java index 316d034b..9343ce19 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java @@ -2,7 +2,7 @@ package com.ruoyi.iot.tdengine.config; import com.alibaba.druid.pool.DruidDataSource; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.iot.tdengine.dao.TDDeviceLogMapper; +import com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; @@ -31,7 +31,7 @@ import java.util.List; * 开发人: wxy */ @Configuration -@MapperScan(basePackages = {"com.ruoyi.iot.tdengine.dao"}, sqlSessionTemplateRef = "tdengineSqlSessionTemplate") +@MapperScan(basePackages = {"com.ruoyi.iot.tdengine.mapper"}, sqlSessionTemplateRef = "tdengineSqlSessionTemplate") @ConditionalOnProperty(name = "spring.datasource.druid.tdengine-server.enabled", havingValue = "true") public class TDengineConfig { @@ -64,6 +64,16 @@ public class TDengineConfig { return new SqlSessionTemplate(sqlSessionFactory); } + +// @Bean +// @ConditionalOnProperty(name = "spring.datasource.druid.tdengine-server.enabled", havingValue = "true") +// public TDDeviceLogMapper genTdengineLogMapper(@Qualifier("tDengineDataSource") TDDeviceLogMapper mapper) { +// if(this.deviceLogMapper==null){ +// this.deviceLogMapper=mapper; +// } +// return this.deviceLogMapper; +// } + public TDDeviceLogMapper getTDengineLogMapper() { return deviceLogMapper; } diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/mapper/DatabaseMapper.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/mapper/DatabaseMapper.java new file mode 100644 index 00000000..076e66ac --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/mapper/DatabaseMapper.java @@ -0,0 +1,25 @@ +package com.ruoyi.iot.tdengine.mapper; + +import org.springframework.stereotype.Repository; + +/** + * @package com.ruoyi.mysql.mysql.tdengine + * 类名: DatabaseMapper + * 描述: TODO + * 时间: 2022/5/16,0016 1:27 + * 开发人: wxy + */ +@Repository +public interface DatabaseMapper { + + int createDB(); + + int dropDatabase(); + + int useDatabase(); + + int createTable(); + + + +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/mapper/TDDeviceLogMapper.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/mapper/TDDeviceLogMapper.java new file mode 100644 index 00000000..99aa0f6a --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/mapper/TDDeviceLogMapper.java @@ -0,0 +1,42 @@ +package com.ruoyi.iot.tdengine.mapper; + +import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.model.MonitorModel; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.lang.management.MonitorInfo; +import java.util.Date; +import java.util.List; + +/** + * @package com.ruoyi.mysql.mysql.tdengine + * 类名: DatabaseMapper + * 描述: TODO + * 时间: 2022/5/16,0016 1:27 + * 开发人: wxy + */ +@Repository +public interface TDDeviceLogMapper { + + + int createDB( String database); + + int createSTable(String database); + + int createTable(String database,String deviceId); + + int save(@Param("database") String database,@Param("device") DeviceLog deviceLog); + + List selectSTable(String database,DeviceLog deviceLog); + + int delete(String dbName, DeviceLog deviceLog); + +// List selectLogListByPage(String dbName, Integer pageSize, Integer pageNum, String deviceNum, Date beginDate, Date endDate); + + List selectLogList(String dbName, Long deviceId, String serialNumber, Long isMonitor, Long logType, Date beginDate, Date endDate); + + List selectMonitorList(@Param("database") String database, @Param("device") DeviceLog deviceLog); + + List selectDeviceLogList(@Param("database") String database,@Param("device") DeviceLog deviceLog); +} diff --git a/springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml b/springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml index 4cc118cf..a2925db9 100644 --- a/springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml +++ b/springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml @@ -2,7 +2,7 @@ - + diff --git a/springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml b/springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml index 461625c4..a17ef4d2 100644 --- a/springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml +++ b/springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml @@ -2,7 +2,7 @@ - + diff --git a/vue/src/assets/images/code.jpg b/vue/src/assets/images/code.jpg new file mode 100644 index 00000000..51084994 Binary files /dev/null and b/vue/src/assets/images/code.jpg differ diff --git a/vue/src/views/index.vue b/vue/src/views/index.vue index 771de332..831fe857 100644 --- a/vue/src/views/index.vue +++ b/vue/src/views/index.vue @@ -1,5 +1,45 @@ diff --git a/vue/src/views/iot/clientDetails/index.vue b/vue/src/views/iot/clientDetails/index.vue index 5f462422..5cbed3d5 100644 --- a/vue/src/views/iot/clientDetails/index.vue +++ b/vue/src/views/iot/clientDetails/index.vue @@ -1,7 +1,6 @@