Files
movecheck/src/utils/sendMqtt.js
2025-11-05 10:07:59 +08:00

426 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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,
}