// MQTT工具包 - 兼容H5、App、微信小程序 // 参考:https://blogs.seecsdn.cn/online/2025-09-27/0ecf1401e23b25be5f8c7e4377d8b5dd.html let mqtturl; // #ifdef H5 mqtturl = "ws://122.51.194.184:8083/mqtt"; import * as mqtt from "mqtt/dist/mqtt.min.js"; // #endif // #ifdef APP-PLUS mqtturl = "wx://122.51.194.184:8083/mqtt"; import * as mqtt from "mqtt/dist/mqtt.min.js"; //#endif // #ifdef MP-WEIXIN mqtturl = "wx://122.51.194.184:8083/mqtt"; import * as mqtt from "mqtt/dist/mqtt.min.js"; //#endif // #ifdef MP-ALIPAY mqtturl = "alis://122.51.194.184:8083/mqtt"; import * as mqtt from "@/utils/mqtt.min.js"; //#endif function messageid2() { // 2位随机数 return Math.floor(Math.random() * (99 - 10)) + 10; } var client; // 重连计数器,记录连续失败的重连次数 let reconnectAttempts = 0; const MAX_RECONNECT_ATTEMPTS = 5; // 最大重连次数 // 创建MQTT连接 const createMqtt = () => { let options = { keepalive: 30, clientId: `mobile-inspection-system-${messageid2()}`, // 客户端ID protocolId: 'MQTT', username: "dmbroker", password: "qwer1234", protocolVersion: 4, clean: true, reconnectPeriod: 1000, // 恢复自动重连,1秒重连一次 connectTimeout: 5000, // 5s超时时间 topic: "HDYDCJ_01_UP", rejectUnauthorized: false, // #ifdef MP-ALIPAY my: my,//注意这里的my //#endif } try { // 检查是否已经超过最大重连次数 if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) { console.log(`❌ 已重连${MAX_RECONNECT_ATTEMPTS}次失败,停止继续连接`); uni.hideLoading(); uni.showToast({ title: `连接失败,已重试${MAX_RECONNECT_ATTEMPTS}次`, icon: 'error', duration: 3000 }); return; } if (!client) { console.log('🔧 开始创建MQTT连接...'); console.log('🔧 MQTT URL:', mqtturl); console.log('🔧 连接选项:', options); console.log('🔧 当前平台:', // #ifdef H5 'H5' // #endif // #ifdef APP-PLUS 'APP-PLUS' // #endif // #ifdef MP-WEIXIN 'MP-WEIXIN' // #endif // #ifdef MP-ALIPAY 'MP-ALIPAY' // #endif ) console.log(`🔄 当前重连次数: ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS}`); // 显示连接loading uni.showLoading({ title: 'MQTT连接中...', // mask: true }); client = mqtt.connect(mqtturl, options); initEventHandleMqtt(options.topic); } else { console.log('🔧 MQTT客户端已存在,跳过创建'); } } catch (e) { console.error('❌ MQTT连接创建失败:', e); console.error('❌ 错误详情:', e.message); console.error('❌ 错误堆栈:', e.stack); // 连接失败时增加重连计数器 reconnectAttempts++; console.log(`❌ 连接失败,当前重连次数: ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS}`); // 检查是否超过最大重连次数 if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) { console.log(`❌ 已达到最大重连次数${MAX_RECONNECT_ATTEMPTS}次,停止连接`); uni.hideLoading(); uni.showToast({ title: `连接失败,已重试${MAX_RECONNECT_ATTEMPTS}次`, icon: 'error', duration: 3000 }); client = null; return; } // 连接失败时隐藏loading uni.hideLoading(); // uni.showToast({ // title: 'MQTT连接失败', // icon: 'error', // duration: 3000 // }); // 重置客户端,允许重试 client = null; } }; //建立连接 const initEventHandleMqtt = (topicUrl) => { // 当连接成功时触发 client.on("connect", function() { uni.hideLoading(); console.log("✅ MQTT连接成功"); // 连接成功,重置重连计数器 reconnectAttempts = 0; console.log("✅ 重置重连计数器"); // 显示连接成功提示 // uni.showToast({ // title: 'MQTT连接成功', // icon: 'success', // duration: 2000 // }); //订阅主题 client.subscribe(topicUrl, function(err) { if (err) { console.error("❌ MQTT订阅主题失败:", err); uni.showToast({ title: '订阅主题失败', icon: 'error', duration: 3000 }); } else { sendMqttDataRecall({ command: 'Upload immediately', }) // console.log("✅ MQTT订阅主题成功:", topicUrl); } }); }); //如果mqttws订阅主题成功,那么这里就是当接收到自己订阅主题的处理逻辑 client.on("message", function(topic, message) { try { console.log('📨 收到MQTT消息:'); console.log('主题:', topic); console.log('消息内容:', message.toString()); // 获取信息 const mqttData = JSON.parse(message.toString()); // console.log('📋 解析后的数据:', mqttData); // 如果是数组,打印数组信息 if (Array.isArray(mqttData)) { mqttData.forEach((item, index) => { if (item.Device) { // console.log(`🔍 设备类型[${index}]: ${item.Device}`); } }); } // 传递信息 uni.$emit("mqttData", mqttData); } catch (error) { console.error('❌ 处理MQTT消息失败:', error); console.error('原始消息:', message.toString()); } }); // 当断开连接后,经过重连间隔时间重新自动连接到 Broker 时触发 client.on('reconnect', function() { reconnectAttempts++; console.log(`🔄 MQTT重新连接中... (第${reconnectAttempts}次重连)`); // 检查是否超过最大重连次数 if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) { console.log(`❌ 已达到最大重连次数${MAX_RECONNECT_ATTEMPTS}次,停止重连`); uni.hideLoading(); uni.showToast({ title: `连接失败,已重试${MAX_RECONNECT_ATTEMPTS}次`, icon: 'error', duration: 3000 }); // 停止重连,关闭客户端 if (client) { client.end(); client = null; } return; } uni.showLoading({ title: `重新连接中... (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})` }); }); // 当客户端无法成功连接时或发生解析错误时触发,参数 error 为错误信息 client.on("error", function(err) { console.error('❌ MQTT连接错误:', err); uni.hideLoading(); uni.showToast({ title: 'MQTT连接错误', icon: 'error', duration: 3000 }); }); // 在收到 Broker 发送过来的断开连接的报文时触发 client.on('disconnect', function() { console.log('⚠️ MQTT连接断开'); uni.hideLoading(); }); // 在断开连接以后触发 client.on("close", function() { console.log('🔌 MQTT连接关闭'); uni.hideLoading(); }); // 当客户端下线时触发 client.on("offline", function() { console.log('📴 MQTT客户端离线'); uni.hideLoading(); }); }; //强制断开Mqtt const closeMqtt = () => { if (client) { console.log('🔌 强制断开MQTT连接'); uni.hideLoading(); client.end(); client = null; } // 断开连接时重置重连计数器 reconnectAttempts = 0; console.log('🔌 重置重连计数器'); }; // 使用pingResp心跳判断客户端和服务端是否还在连接着 const judgeBeat = () => { if (client && client.pingResp === false) { console.log('💔 MQTT心跳停止,准备重连'); uni.showLoading({ title: "心跳停止,等待重连..." }); closeMqtt(); createMqtt(); } }; // 获取连接状态 const getConnectionStatus = () => { if (!client) { // console.log('🔍 连接状态检查: 客户端不存在'); return false; } const isConnected = client.connected; // console.log('🔍 连接状态检查:', { // clientExists: !!client, // connected: isConnected, // readyState: client.stream ? client.stream.readyState : 'unknown' // }); return isConnected; }; // 手动重连函数 const manualReconnect = () => { console.log('🔄 手动触发重连'); // 手动重连时重置计数器,给用户重新开始的机会 reconnectAttempts = 0; console.log('🔄 重置重连计数器,开始新的连接尝试'); closeMqtt(); setTimeout(() => { createMqtt(); }, 300); }; // 发送MQTT数据(单独订阅HDYDCJ_01_DOWN) const sendMqttData = (data) => { try { if (!client || !client.connected) { console.error('❌ MQTT客户端未连接,无法发送数据'); uni.showToast({ title: 'MQTT未连接', icon: 'error', duration: 2000 }); return false; } const message = JSON.stringify(data); console.log('📤 发送MQTT数据:', data); console.log('📤 发送消息内容:', message); console.log('📤 发送到主题: HDYDCJ_01_DOWN'); // 先订阅HDYDCJ_01_DOWN主题(如果还没有订阅) client.subscribe("HDYDCJ_01_DOWN", (err) => { if (err) { console.error('❌ 订阅HDYDCJ_01_DOWN失败:', err); } else { console.log('✅ 订阅HDYDCJ_01_DOWN成功'); } }); // 发送数据到HDYDCJ_01_DOWN主题 client.publish("HDYDCJ_01_DOWN", message, (err) => { if (err) { console.error('❌ MQTT数据发送失败:', err); uni.showToast({ title: '数据发送失败', icon: 'error', duration: 2000 }); } else { console.log('✅ MQTT数据发送成功'); // uni.showToast({ // title: '数据发送成功', // icon: 'success', // duration: 1500 // }); } }); return true; } catch (error) { console.error('❌ 发送MQTT数据异常:', error); uni.showToast({ title: '发送数据异常', icon: 'error', duration: 2000 }); return false; } }; // 发送MQTT数据(单独订阅HDYDCJ_01_RECALL) const sendMqttDataRecall = (data) => { try { if (!client || !client.connected) { console.error('❌ MQTT客户端未连接,无法发送数据'); uni.showToast({ title: 'MQTT未连接', icon: 'error', duration: 2000 }); return false; } const message = JSON.stringify(data); // 先订阅HDYDCJ_01_RECALL主题(如果还没有订阅) client.subscribe("HDYDCJ_01_RECALL", (err) => { if (err) { console.error('❌ 订阅HDYDCJ_01_RECALL失败:', err); } else { console.log('✅ 订阅HDYDCJ_01_RECALL成功'); } }); // 发送数据到HDYDCJ_01_RECALL主题 client.publish("HDYDCJ_01_RECALL", message, (err) => { if (err) { uni.showToast({ title: '数据发送失败', icon: 'error', duration: 2000 }); } else { // uni.showToast({ // title: '数据发送成功', // icon: 'success', // duration: 1500 // }); } }); return true; } catch (error) { uni.showToast({ title: '发送数据异常', icon: 'error', duration: 2000 }); return false; } }; export { createMqtt, closeMqtt, judgeBeat, getConnectionStatus, manualReconnect, sendMqttData, sendMqttDataRecall, client, }