/** * 智能农业小程序 - MQTT全局工具类(uniapp+小程序适配版) * 核心设计: * 1. 配置暂时写死全局,后续可替换为登录后从数据字典获取 * 2. clientId仅随机生成(无需关联userId),保证唯一性即可 * 3. 同步方法为主,全局统一管理连接/订阅/发布,多页面复用 */ // 引入小程序版MQTT核心库(确保mqtt.min.js在utils目录) import mqtt from './mqtt.min.js' // ===================== MQTT配置(暂时写死,TODO:后续从数据字典获取)===================== const MQTT_CONFIG = { server: 'ws://122.51.109.52:9001/mqtt', // 替换为你的MQTT服务器地址 username: 'admin', // 替换为通用账号 password: 'Admin#12345678', // 替换为通用密码 clean: true, host: '122.51.109.52', port: 9001, reconnectPeriod: 5000, // 重连间隔 connectTimeout: 10000, // 连接超时 keepalive: 60, // 心跳时间 protocol: 'ws' } // ===================== MQTT全局状态管理 ===================== const mqttState = { client: null, // MQTT客户端实例 isConnected: false, // 连接状态(同步标记) subscribeList: [], // 全局订阅列表(登录后赋值) options: { // MQTT连接选项 clientId: '', // 仅随机生成,无需关联userId ...MQTT_CONFIG // 合并基础配置 }, onMessageCallback: null // 全局消息回调(各页面自定义) } /** * 初始化MQTT配置(生成随机clientId,无需传入userId) * @returns {Boolean} - 是否配置成功 */ export function initMqttConfig() { try { // 仅随机生成clientId(保证唯一性,避免连接冲突) mqttState.options.clientId = `wx_mqtt_${Math.random().toString(16).substr(2, 10)}` // 重置旧状态,避免干扰 mqttState.isConnected = false mqttState.client = null console.log('MQTT配置初始化成功,clientId:', mqttState.options.clientId) return true } catch (err) { uni.showToast({ title: '设备连接异常', icon: 'none', duration: 2000 }) console.error('MQTT配置初始化失败:', err) return false } } /** * 建立MQTT连接(初始化后调用,同步返回触发状态) * @returns {Boolean} - 是否成功触发连接 */ export function connectMqtt() { // 前置校验:是否已初始化配置 if (!mqttState.options.clientId) { uni.showToast({ title: '设备连接异常', icon: 'none' }) console.error('MQTT连接失败:请先调用initMqttConfig初始化配置') return false } // 避免重复连接 if (mqttState.isConnected && mqttState.client) { console.log('MQTT已连接,无需重复操作') return true } try { // 创建客户端实例(同步操作) // mqttState.client = mqtt.connect(MQTT_CONFIG.server, mqttState.options) // #ifdef MP-WEIXIN MQTT_CONFIG.protocol = 'wxs'; // #endif mqttState.client = mqtt.connect({ host: MQTT_CONFIG.host, port: MQTT_CONFIG.port, clientId: mqttState.options.clientId, username: MQTT_CONFIG.username, password: MQTT_CONFIG.password, // 关键:指定用小程序的Socket protocol: MQTT_CONFIG.protocol // 或'ws',根据你的MQTT服务协议 }) // 监听核心事件(异步,同步更新状态) mqttState.client.on('connect', () => { console.log('MQTT连接成功') mqttState.isConnected = true // 连接成功后自动订阅全局列表 subscribeAllTopics() }) mqttState.client.on('close', () => { console.log('MQTT连接断开') mqttState.isConnected = false }) mqttState.client.on('error', (err) => { uni.showToast({ title: '设备连接异常', icon: 'none' }) console.error('MQTT连接错误:', err) mqttState.isConnected = false }) // 全局接收消息,转发给页面自定义回调 mqttState.client.on('message', (topic, payload) => { const message = payload.toString() // console.log(`收到MQTT消息:topic=${topic},message=${message}`) if (typeof mqttState.onMessageCallback === 'function') { mqttState.onMessageCallback(topic, message) } }) return true } catch (err) { uni.showToast({ title: '设备连接异常', icon: 'none' }) console.error('MQTT连接创建失败:', err) mqttState.isConnected = false return false } } /** * 设置页面专属消息回调(各页面独立处理消息) * @param {Function} callback - (topic, message) => {} */ export function setOnMessageCallback(callback) { if (typeof callback === 'function') { mqttState.onMessageCallback = callback console.log('MQTT消息回调已注册') } else { console.error('MQTT回调必须是函数类型') } } /** * 移除消息回调(页面卸载时调用,避免内存泄漏) */ export function removeOnMessageCallback() { mqttState.onMessageCallback = null console.log('MQTT消息回调已移除') } /** * 更新全局订阅列表(登录后调用,自动订阅) * @param {Array} list - 订阅主题列表 ['topic1', 'topic2'] * @returns {Boolean} - 是否更新成功 */ export function updateSubscribeList(list) { if (!Array.isArray(list)) { uni.showToast({ title: '设备连接异常', icon: 'none' }) console.error('订阅列表必须是数组') return false } mqttState.subscribeList = [...list] console.log('MQTT订阅列表已更新:', list) // 已连接则立即订阅 if (mqttState.isConnected) { subscribeAllTopics() } return true } /** * 内部方法:订阅所有全局主题 */ function subscribeAllTopics() { const { isConnected, client, subscribeList } = mqttState if (!isConnected || !client || subscribeList.length === 0) { console.warn('MQTT订阅跳过:未连接或列表为空') return } client.subscribe(subscribeList, { qos: 0 }, (err) => { if (err) { uni.showToast({ title: '设备连接异常', icon: 'none' }) console.error('MQTT订阅失败:', err) } else { console.log(`MQTT成功订阅:${subscribeList.join(', ')}`) } }) } /** * 发布MQTT消息(同步调用) * @param {String} topic - 发布主题 * @param {String/Object} message - 发布内容 * @returns {Boolean} - 是否触发发布成功 */ export function publishMqtt(topic, message) { const { isConnected, client } = mqttState if (!isConnected || !client) { uni.showToast({ title: '控制异常', icon: 'none' }) console.error('MQTT发布失败:未连接') return false } if (!topic) { uni.showToast({ title: '控制异常', icon: 'none' }) console.error('MQTT发布失败:主题为空') return false } try { const msg = typeof message === 'object' ? JSON.stringify(message) : String(message) client.publish(topic, msg, (err) => { if (err) { uni.showToast({ title: '控制异常', icon: 'none' }) console.error(`MQTT发布失败:topic=${topic},err=${err}`) } else { console.log(`MQTT发布成功:topic=${topic},message=${msg}`) } }) return true } catch (err) { uni.showToast({ title: '控制异常', icon: 'none' }) console.error('MQTT发布异常:', err) return false } } /** * 断开MQTT连接(登出/小程序切后台时调用) * @returns {Boolean} - 是否断开成功 */ export function disconnectMqtt() { if (!mqttState.client) { console.log('MQTT无客户端实例,无需断开') resetMqttState() return true } try { mqttState.client.end(true) // 强制断开 resetMqttState() console.log('MQTT连接已断开') return true } catch (err) { uni.showToast({ title: '设备连接异常', icon: 'none' }) console.error('MQTT断开失败:', err) return false } } /** * 重置MQTT状态(内部方法) */ function resetMqttState() { mqttState.isConnected = false mqttState.client = null mqttState.subscribeList = [] mqttState.onMessageCallback = null // 保留clientId,直到下一次初始化覆盖 } /** * 获取当前MQTT状态(同步) * @returns {Object} - 状态副本 */ export function getMqttState() { return { isConnected: mqttState.isConnected, subscribeList: [...mqttState.subscribeList], clientId: mqttState.options.clientId } } // 导出所有方法(全局调用) export default { initMqttConfig, connectMqtt, setOnMessageCallback, removeOnMessageCallback, updateSubscribeList, publishMqtt, disconnectMqtt, getMqttState }