2025-07-07 11:27:24 +08:00
|
|
|
|
import mqtt from 'mqtt/dist/mqtt.js';
|
2025-07-05 14:49:26 +08:00
|
|
|
|
|
|
|
|
|
const MQTT_BROKER_URL = 'ws://your-mqtt-broker-address:your-port/mqtt'; // 使用 ws:// 或 wss://
|
|
|
|
|
const MQTT_OPTIONS = {
|
2025-07-07 11:27:24 +08:00
|
|
|
|
connectTimeout: 4000,
|
|
|
|
|
clientId: `mqtt_client_${Math.random().toString(16).substr(2, 8)}`,
|
|
|
|
|
username: 'your-username',
|
|
|
|
|
password: 'your-password',
|
|
|
|
|
clean: true,
|
2025-07-05 14:49:26 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-07-07 11:27:24 +08:00
|
|
|
|
let client = null;
|
|
|
|
|
let connectPromise = null;
|
2025-07-05 14:49:26 +08:00
|
|
|
|
|
|
|
|
|
// 连接到 MQTT 代理
|
|
|
|
|
export function connect() {
|
|
|
|
|
if (client && client.connected) {
|
|
|
|
|
return Promise.resolve(client);
|
|
|
|
|
}
|
|
|
|
|
if (connectPromise) {
|
|
|
|
|
return connectPromise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let url = MQTT_BROKER_URL;
|
|
|
|
|
// #ifdef MP-WEIXIN || APP-PLUS
|
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
|
|
console.log(`正在连接到 MQTT 代理: ${url}`);
|
|
|
|
|
client = mqtt.connect(url, MQTT_OPTIONS);
|
|
|
|
|
|
|
|
|
|
connectPromise = new Promise((resolve, reject) => {
|
|
|
|
|
client.on('connect', () => {
|
|
|
|
|
console.log('MQTT 已连接');
|
2025-07-07 11:27:24 +08:00
|
|
|
|
connectPromise = null;
|
2025-07-05 14:49:26 +08:00
|
|
|
|
resolve(client);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
client.on('reconnect', () => {
|
|
|
|
|
console.log('MQTT 正在重新连接...');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
client.on('error', (err) => {
|
|
|
|
|
console.error('MQTT 连接错误:', err);
|
2025-07-07 11:27:24 +08:00
|
|
|
|
if (connectPromise) {
|
2025-07-05 14:49:26 +08:00
|
|
|
|
reject(err);
|
|
|
|
|
}
|
2025-07-07 11:27:24 +08:00
|
|
|
|
connectPromise = null;
|
2025-07-05 14:49:26 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
client.on('close', () => {
|
|
|
|
|
console.log('MQTT 连接已关闭');
|
|
|
|
|
connectPromise = null;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
client.on('offline', () => {
|
|
|
|
|
console.log('MQTT 客户端离线');
|
|
|
|
|
connectPromise = null;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return connectPromise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 断开 MQTT 连接
|
|
|
|
|
export function disconnect() {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
if (client) {
|
|
|
|
|
console.log('正在断开 MQTT 客户端...');
|
|
|
|
|
client.end(true, (err) => { // true 表示强制关闭,丢弃未发送的消息
|
|
|
|
|
if (err) {
|
|
|
|
|
console.error('MQTT 断开连接时出错:', err);
|
|
|
|
|
} else {
|
|
|
|
|
console.log('MQTT 已成功断开连接');
|
|
|
|
|
}
|
|
|
|
|
client = null;
|
|
|
|
|
connectPromise = null;
|
|
|
|
|
resolve();
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
resolve();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 发布消息
|
|
|
|
|
export async function publish(topic, message, options = { qos: 0, retain: false }) {
|
|
|
|
|
if (!client || !client.connected) {
|
|
|
|
|
console.warn('MQTT 客户端未连接。正在尝试连接...');
|
|
|
|
|
try {
|
|
|
|
|
await connect(); // 发布前确保已连接
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('发布前连接失败:', error);
|
|
|
|
|
uni.showToast({ title: 'MQTT 连接失败', icon: 'none' });
|
|
|
|
|
return Promise.reject('MQTT 客户端未连接');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
client.publish(topic, message, options, (err) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
console.error('MQTT 发布错误:', err);
|
|
|
|
|
reject(err);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(`MQTT 消息已发布到主题 ${topic}:`, message);
|
|
|
|
|
resolve();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 订阅主题
|
|
|
|
|
export async function subscribe(topic, options = { qos: 0 }) {
|
|
|
|
|
if (!client || !client.connected) {
|
|
|
|
|
console.warn('MQTT 客户端未连接。正在尝试连接...');
|
|
|
|
|
try {
|
|
|
|
|
await connect(); // 订阅前确保已连接
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('订阅前连接失败:', error);
|
|
|
|
|
uni.showToast({ title: 'MQTT 连接失败', icon: 'none' });
|
|
|
|
|
return Promise.reject('MQTT 客户端未连接');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
client.subscribe(topic, options, (err, granted) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
console.error('MQTT 订阅错误:', err);
|
|
|
|
|
reject(err);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(`MQTT 已订阅主题: ${granted[0].topic} 服务质量 (QoS): ${granted[0].qos}`);
|
|
|
|
|
resolve(granted);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 取消订阅主题
|
|
|
|
|
export function unsubscribe(topic) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (client && client.connected) {
|
|
|
|
|
client.unsubscribe(topic, (err) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
console.error('MQTT 取消订阅错误:', err);
|
|
|
|
|
reject(err);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(`MQTT 已取消订阅主题: ${topic}`);
|
|
|
|
|
resolve();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
console.warn('MQTT 客户端未连接,无法取消订阅。');
|
2025-07-07 11:27:24 +08:00
|
|
|
|
resolve();
|
2025-07-05 14:49:26 +08:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理传入的消息
|
|
|
|
|
export function onMessage(callback) {
|
|
|
|
|
if (client) {
|
|
|
|
|
client.on('message', callback); // 回调格式: (topic, message, packet) => { ... }
|
|
|
|
|
} else {
|
|
|
|
|
const checkClientInterval = setInterval(() => {
|
|
|
|
|
if (client) {
|
|
|
|
|
client.on('message', callback);
|
|
|
|
|
clearInterval(checkClientInterval);
|
|
|
|
|
} else if (connectPromise === null && client === null) {
|
|
|
|
|
console.warn('MQTT 客户端未初始化以处理 onMessage,且没有连接尝试正在进行中。');
|
|
|
|
|
clearInterval(checkClientInterval);
|
|
|
|
|
}
|
2025-07-07 11:27:24 +08:00
|
|
|
|
}, 100);
|
2025-07-05 14:49:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
export function getClient() {
|
|
|
|
|
return client;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isConnected() {
|
|
|
|
|
return client && client.connected;
|
|
|
|
|
}
|