mqtt优化

This commit is contained in:
kerwincui
2022-07-30 00:19:02 +08:00
parent fd7f186ccc
commit e94a770425
3 changed files with 353 additions and 118 deletions

View File

@@ -39,6 +39,9 @@ import DictData from '@/components/DictData'
import echarts from 'echarts'
// 一键复制粘贴板组件
import VueClipboard from 'vue-clipboard2'
// Mqtt工具
import mqttTool from '@/utils/mqttTool'
@@ -55,6 +58,7 @@ Vue.prototype.selectDictLabels = selectDictLabels
Vue.prototype.download = download
Vue.prototype.handleTree = handleTree
Vue.prototype.$echarts = echarts
Vue.prototype.$mqttTool = mqttTool
// 全局组件挂载
Vue.component('DictTag', DictTag)

140
vue/src/utils/mqttTool.js Normal file
View File

@@ -0,0 +1,140 @@
import mqtt from 'mqtt'
import { getToken } from "@/utils/auth";
let mqttTool = {
client: null,
}
/** 连接Mqtt */
mqttTool.connect = function () {
let options = {
username: "wumei-smart",
password: getToken(),
cleanSession: true,
keepAlive: 30,
clientId: 'web-' + Math.random().toString(16).substr(2),
connectTimeout: 10000
}
// 配置Mqtt地址
// let url = "ws://" + window.location.hostname + ":8083/mqtt";
console.log("mqtt地址", process.env.VUE_APP_EMQX_SERVER_URL);
mqttTool.client = mqtt.connect(process.env.VUE_APP_EMQX_SERVER_URL, options);
mqttTool.client.on("connect", (e) => {
console.log('mqtt连接成功');
});
// 重新连接
mqttTool.client.on('reconnect', (error) => {
console.log('正在重连:', error)
});
// 发生错误
mqttTool.client.on('error', (error) => {
console.log('Mqtt客户端连接失败', error)
mqttTool.client.end();
})
// 断开连接
mqttTool.client.on('close', function (res) {
console.log('已断开Mqtt连接');
});
}
/** 断开连接 */
mqttTool.end = function () {
return new Promise((resolve, reject) => {
if (mqttTool.client == null) {
resolve('未连接')
console.log("未连接")
return;
}
mqttTool.client.end()
mqttTool.client = null
console.log('Mqtt服务器已断开连接');
resolve('连接终止')
})
}
/** 重新连接 */
mqttTool.reconnect = function () {
return new Promise((resolve, reject) => {
if (mqttTool.client == null) {
// 调用resolve方法Promise变为操作成功状态fulfilled
resolve('未连接')
console.log("未连接")
return;
}
console.log('正在重连...', res);
mqttTool.client.reconnect()
})
}
/** 消息订阅 */
mqttTool.subscribe = function (topics) {
return new Promise((resolve, reject) => {
if (mqttTool.client == null) {
resolve('未连接')
console.log("未连接")
uni.showToast({
icon: 'none',
title: 'mqtt未连接',
});
return;
}
mqttTool.client.subscribe(topics, {
qos: 1
}, function (err, res) {
console.log("订阅主题:", topics);
if (!err && res.length > 0) {
console.log("订阅成功")
resolve('订阅成功')
} else {
console.log("订阅失败,主题可能已经订阅")
resolve('订阅失败')
return;
}
})
})
}
/** 取消订阅 */
mqttTool.unsubscribe = function (topics) {
return new Promise((resolve, reject) => {
if (mqttTool.client == null) {
resolve('未连接')
console.log("未连接")
return;
}
mqttTool.client.unsubscribe(topics, function (err) {
if (!err) {
resolve('取消订阅成功')
console.log("取消订阅成功")
} else {
resolve('取消订阅失败')
console.log("取消订阅失败")
return;
}
})
})
}
mqttTool.publish = function (topic, message, name) {
return new Promise((resolve, reject) => {
if (mqttTool.client == null) {
resolve('Mqtt客户端未连接')
console.log("Mqtt客户端未连接")
return;
}
mqttTool.client.publish(topic, message, { qos: 1 }, function (err) {
console.log('发送主题:', topic);
console.log('发送内容:', message);
if (!err) {
if (topic.indexOf('offline') > 0) {
console.log("[ " + name + " ] 影子指令发送成功");
resolve("[ " + name + " ] 影子指令发送成功");
} else {
console.log("[ " + name + " ] 指令发送成功");
resolve("[ " + name + " ] 指令发送成功");
}
} else {
console.log("[ " + name + " ] 指令发送失败");
reject("[ " + name + " ] 指令发送失败");
return;
}
})
})
}
export default mqttTool

View File

@@ -183,16 +183,12 @@
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- Mqtt通讯 -->
<mqttClient ref="mqttClient" :publish="publish" :subscribes="subscribes" @callbackEvent="mqttCallback($event)" />
</el-card>
</div>
</template>
<script>
import * as echarts from 'echarts';
import mqttClient from './mqtt-client.vue'
import {
listDeviceShort,
delDevice,
@@ -207,9 +203,7 @@ import {
export default {
name: "Device",
dicts: ['iot_device_status', 'iot_is_enable', 'iot_location_way'],
components: {
mqttClient
},
components: {},
data() {
return {
// 实时监测间隔
@@ -281,7 +275,7 @@ export default {
this.queryParams.groupId = Number(groupId);
this.queryParams.productId = null;
}
this.getList();
this.connectMqtt();
},
activated() {
const time = this.$route.query.t;
@@ -308,6 +302,14 @@ export default {
}
},
methods: {
/* 连接Mqtt消息服务器 */
async connectMqtt() {
if (this.$mqttTool.client == null) {
await this.$mqttTool.connect();
}
this.mqttCallback();
this.getList();
},
/** 查询设备分组列表 */
getGroupList() {
this.loading = true;
@@ -386,127 +388,129 @@ export default {
}
if (topic != "") {
// 发布
this.publish = {
topic: topic,
message: message,
name: model.name
};
this.$mqttTool.publish(topic, message, model.name).then(res => {
this.$modal.notifySuccess(res);
}).catch(res => {
this.$modal.notifyError(res);
});
}
},
/** 接收到Mqtt回调 */
mqttCallback(data) {
let topics = [];
topics = data.topic.split("/");
let productId = topics[1];
let deviceNum = topics[2]
if (topics[3] == "status") {
// 更新列表中设备的状态
for (let i = 0; i < this.deviceList.length; i++) {
if (this.deviceList[i].serialNumber == deviceNum) {
this.deviceList[i].status = data.message.status;
this.deviceList[i].isShadow = data.message.isShadow;
this.deviceList[i].rssi = data.message.rssi;
return;
}
}
// 更新实时监测模型的状态
if (this.monitorDevice.serialNumber == deviceNum) {
this.monitorDevice.status = data.message.status;
this.monitorDevice.isShadow = data.message.isShadow;
this.monitorDevice.rssi = data.message.rssi;
}
}
if (topics[3] == "monitor") {
// 实时监测
this.chartLoading = false;
for (let k = 0; k < data.message.length; k++) {
let value = data.message[k].value;
let id = data.message[k].id;
let remark = data.message[k].remark;
// 数据加载到图表
for (let i = 0; i < this.dataList.length; i++) {
if (id == this.dataList[i].id) {
if (this.dataList[i].length > 50) {
this.dataList[i].shift();
}
this.dataList[i].data.push([this.getTime(), value]);
// 更新图表
this.chart[i].setOption({
series: [{
data: this.dataList[i].data
}]
});
/* Mqtt回调处理 */
mqttCallback() {
this.$mqttTool.client.on('message', (topic, message, buffer) => {
let topics = topic.split('/');
let productId = topics[1];
let deviceNum = topics[2];
message = JSON.parse(message.toString());
if (topics[3] == 'status') {
console.log('接收到【设备状态】主题:', topic);
console.log('接收到【设备状态】内容:', message);
// 更新列表中设备的状态
for (let i = 0; i < this.deviceList.length; i++) {
if (this.deviceList[i].serialNumber == deviceNum) {
this.deviceList[i].status = message.status;
this.deviceList[i].isShadow = message.isShadow;
this.deviceList[i].rssi = message.rssi;
return;
}
}
}
}
if (topics[3] == 'property' || topics[3] == 'function') {
// 更新列表中设备的属性
for (let i = 0; i < this.deviceList.length; i++) {
if (this.deviceList[i].serialNumber == deviceNum) {
for (let j = 0; j < data.message.length; j++) {
let isComplete = false;
// 布尔类型
for (let k = 0; k < this.deviceList[i].boolList.length && !isComplete; k++) {
if (this.deviceList[i].boolList[k].id == data.message[j].id) {
this.deviceList[i].boolList[k].shadow = data.message[j].value;
isComplete = true;
break;
}
}
// 枚举类型
for (let k = 0; k < this.deviceList[i].enumList.length && !isComplete; k++) {
if (this.deviceList[i].enumList[k].id == data.message[j].id) {
this.deviceList[i].enumList[k].shadow = data.message[j].value;
isComplete = true;
break;
}
}
// 字符串类型
for (let k = 0; k < this.deviceList[i].stringList.length && !isComplete; k++) {
if (this.deviceList[i].stringList[k].id == data.message[j].id) {
this.deviceList[i].stringList[k].shadow = data.message[j].value;
isComplete = true;
break;
}
}
// 数组类型
for (let k = 0; k < this.deviceList[i].arrayList.length && !isComplete; k++) {
if (this.deviceList[i].arrayList[k].id == data.message[j].id) {
this.deviceList[i].arrayList[k].shadow = data.message[j].value;
isComplete = true;
break;
}
}
// 整数类型
for (let k = 0; k < this.deviceList[i].integerList.length && !isComplete; k++) {
if (this.deviceList[i].integerList[k].id == data.message[j].id) {
this.deviceList[i].integerList[k].shadow = data.message[j].value;
isComplete = true;
break;
}
}
// 小数类型
for (let k = 0; k < this.deviceList[i].decimalList.length && !isComplete; k++) {
if (this.deviceList[i].decimalList[k].id == data.message[j].id) {
this.deviceList[i].decimalList[k].shadow = data.message[j].value;
isComplete = true;
break;
if (topics[3] == "monitor") {
console.log('接收到【设备状态】主题:', topic);
console.log('接收到【设备状态】内容:', message);
// 实时监测
this.chartLoading = false;
for (let k = 0; k < message.length; k++) {
let value = message[k].value;
let id = message[k].id;
let remark = message[k].remark;
// 数据加载到图表
for (let i = 0; i < this.dataList.length; i++) {
if (id == this.dataList[i].id) {
if (this.dataList[i].length > 50) {
this.dataList[i].shift();
}
this.dataList[i].data.push([this.getTime(), value]);
// 更新图表
this.chart[i].setOption({
series: [{
data: this.dataList[i].data
}]
});
break;
}
}
return;
}
}
}
if (topics[3] == 'property' || topics[3] == 'function') {
console.log('接收到【物模型】主题:', topic);
console.log('接收到【物模型】内容:', message);
// 更新列表中设备的属性
for (let i = 0; i < this.deviceList.length; i++) {
if (this.deviceList[i].serialNumber == deviceNum) {
for (let j = 0; j < message.length; j++) {
let isComplete = false;
// 布尔类型
for (let k = 0; k < this.deviceList[i].boolList.length && !isComplete; k++) {
if (this.deviceList[i].boolList[k].id == message[j].id) {
this.deviceList[i].boolList[k].shadow = message[j].value;
isComplete = true;
break;
}
}
// 枚举类型
for (let k = 0; k < this.deviceList[i].enumList.length && !isComplete; k++) {
if (this.deviceList[i].enumList[k].id == message[j].id) {
this.deviceList[i].enumList[k].shadow = message[j].value;
isComplete = true;
break;
}
}
// 字符串类型
for (let k = 0; k < this.deviceList[i].stringList.length && !isComplete; k++) {
if (this.deviceList[i].stringList[k].id == message[j].id) {
this.deviceList[i].stringList[k].shadow = message[j].value;
isComplete = true;
break;
}
}
// 数组类型
for (let k = 0; k < this.deviceList[i].arrayList.length && !isComplete; k++) {
if (this.deviceList[i].arrayList[k].id == message[j].id) {
this.deviceList[i].arrayList[k].shadow = message[j].value;
isComplete = true;
break;
}
}
// 整数类型
for (let k = 0; k < this.deviceList[i].integerList.length && !isComplete; k++) {
if (this.deviceList[i].integerList[k].id == message[j].id) {
this.deviceList[i].integerList[k].shadow = message[j].value;
isComplete = true;
break;
}
}
// 小数类型
for (let k = 0; k < this.deviceList[i].decimalList.length && !isComplete; k++) {
if (this.deviceList[i].decimalList[k].id == message[j].id) {
this.deviceList[i].decimalList[k].shadow = message[j].value;
isComplete = true;
break;
}
}
}
return;
}
}
}
});
},
/** Mqtt订阅主题 */
/* 订阅消息 */
mqttSubscribe(list) {
// 订阅当前页面设备状态和实时监测
let topics = [];
for (let i = 0; i < list.length; i++) {
let topicStatus = "/" + list[i].productId + "/" + list[i].serialNumber + "/status/post";
let topicStatus = '/' + list[i].productId + '/' + list[i].serialNumber + '/status/post';
let topicMonitor = "/" + list[i].productId + "/" + list[i].serialNumber + "/monitor/post";
let topicProperty = '/' + list[i].productId + '/' + list[i].serialNumber + '/property/post';
let topicFunction = '/' + list[i].productId + '/' + list[i].serialNumber + '/function/post';
@@ -515,8 +519,9 @@ export default {
topics.push(topicProperty);
topics.push(topicFunction);
}
this.subscribes = topics;
this.$mqttTool.subscribe(topics);
},
/** 更新实时监测参数*/
updateMonitorParameters() {
// 清空图表数据
@@ -568,15 +573,101 @@ export default {
this.queryParams.params['beginActiveTime'] = this.daterangeActiveTime[0];
this.queryParams.params['endActiveTime'] = this.daterangeActiveTime[1];
}
this.getGroupList();
listDeviceShort(this.queryParams).then(response => {
this.deviceList = response.rows;
this.total = response.total;
// 订阅设备状态
this.mqttSubscribe(this.deviceList);
// 筛选物模型数量最多6个监测值或3个属性、功能
for (let i = 0; i < this.deviceList.length; i++) {
// 设置boolList中项的默认值解决报错问题,TODO 后端已处理,后期应该可以删除
for (let j = 0; j < this.deviceList[i].boolList.length; j++) {
if (this.deviceList[i].boolList[j].shadow == null) {
this.deviceList[i].boolList[j].shadow = '0';
}
}
let readonlyCount = this.deviceList[i].readOnlyList.length;
if (readonlyCount == 0) {
// 3个属性、功能
this.getThingsCount(3, this.deviceList[i]);
} else if (readonlyCount > 0 && readonlyCount < 3) {
// 2个属性、功能
this.getThingsCount(2, this.deviceList[i]);
} else if (readonlyCount > 2 && readonlyCount < 5) {
// 1个属性、功能
this.getThingsCount(1, this.deviceList[i]);
} else if (readonlyCount > 4 && readonlyCount < 7) {
// 0个属性、功能
this.getThingsCount(0, this.deviceList[i]);
} else {
//保留6个监测值
this.deviceList[i].readOnlyList = this.deviceList[i].readOnlyList.slice(0, 6);
}
}
// 订阅消息
if (this.deviceList && this.deviceList.length > 0) {
this.mqttSubscribe(this.deviceList);
}
this.loading = false;
});
// 获取最新分组列表
this.getGroupList();
},
// 获取物模型数量
getThingsCount(needCount, device) {
let boolCount = device.boolList.length;
let enumCount = device.enumList.length;
let integerCount = device.integerList.length;
let decimalCount = device.decimalList.length;
let stringCount = device.stringList.length;
let arrayCount = device.arrayList.length;
if (boolCount >= needCount) {
device.boolList = device.boolList.slice(0, needCount);
device.enumList = [];
device.integerList = [];
device.decimalList = [];
device.stringList = [];
device.arrayList = [];
return;
} else {
needCount = needCount - boolCount;
}
if (enumCount >= needCount) {
device.enumList = device.enumList.slice(0, needCount);
device.integerList = [];
device.decimalList = [];
device.stringList = [];
device.arrayList = [];
return;
} else {
needCount = needCount - enumCount;
}
if (integerCount >= needCount) {
device.integerList = device.integerList.slice(0, needCount);
device.decimalList = [];
device.stringList = [];
device.arrayList = [];
return;
} else {
needCount = needCount - integerCount;
}
if (decimalCount >= needCount) {
device.decimalList = device.decimalList.slice(0, needCount);
device.stringList = [];
device.arrayList = [];
return;
} else {
needCount = needCount - decimalCount;
}
if (stringCount >= needCount) {
device.stringList = device.stringList.slice(0, needCount);
device.arrayList = [];
return;
} else {
needCount = needCount - stringCount;
}
if (arrayCount >= needCount) {
device.arrayList = device.arrayList.slice(0, needCount);
return;
}
},
// 取消按钮
cancel() {