微信小程序连接MQTT

3,731 阅读4分钟

微信小程序连接MQTT

什么是MQTT

MQTT是一种轻量级通信协议,基于TCP/IP,采用发布-订阅模式,广泛应用于物联网领域。

MQTT的工作原理围绕着三个核心部分:发布者(Publishers)、代理(Broker,也称服务器)和订阅者(Subscribers)。发布者负责发送消息到特定的主题(Topic),代理则接收这些消息并将其转发给所有订阅了该主题的订阅者。这种模式允许设备间异步通信,且设备不需要直接了解彼此的存在,从而降低了系统的复杂性。

微信小程序连接MQTT

下面将以uniapp为例,介绍微信小程序如何连接mqtt

1.前期准备

微信小程序安全要求比较高,与后台服务器之间的通讯必须使用https/wss协议。如果还没有配置mqtt服务器,这里可以使用EMQX的免费公共MQTT服务器进行测试。

微信图片_20240602222317.png

微信小程序还需配置socket合法域名,但是该域名还还没有进行ICP备案,这里配置不了,所以需要在微信开发工具中勾选【不校验合法域名、web-view(业务域名)、TLS版本以及 HTTPS 证书】。
如果已经有MQTT服务器,并且进行了ICP备案的,则不需要勾选【不校验合法域名、web-view(业务域名)、TLS版本以及 HTTPS 证书】,直接按照下图在微信公众平台进行配置即可,配置完成之后需要等待一会才能生效。

1717468727966.png

1717468915830.png

2示例

(1)引入mqtt

uniapp可以使用的mqtt.js版本有v4.1.0 和 v2.18.8

v4.1.0:unpkg.com/mqtt@4.1.0/…

v2.18.8:unpkg.com/mqtt@2.18.8…

在项目根目录下新建utils文件夹,将下载好的对应版本的mqtt.min.js文件放入该文件夹中,然后通过如下方式引入mqtt

import mqtt from "../../utils/mqtt.min.js"

(2)建立连接

data() {
    return {
        client: null,
        connectBtnText: "连接",
        host: "broker.emqx.io",	
        port: 8084,
        clientId: new Date().getTime(),
        subTopic: "testtopic/miniprogram",	// 订阅主题
        pubTopic: "testtopic/miniprogram",	// 发布主题
        pubMsg: "Hello!MQTT!",	// 要发送的信息
        receivedMsg: "",		// 接收到的信息
        mqttOptions: {
            // username: "test",	// 用户名
            // password: "test",	// 密码
            reconnectPeriod: 1000, // 1000毫秒,设置为 0 禁用自动重连,两次重新连接之间的间隔时间
            connectTimeout: 30 * 1000, // 30秒,连接超时时间
        }

    }
},
methods: {
    connectMqtt() {
        try {
            this.connectBtnText = "连接中..."
            // 微信小程序中需要将wss协议写为wxs
            this.client = mqtt.connect(`wxs://${this.host}:${this.port}/mqtt`, {
                ...this.mqttOptions,
                clientId: this.clientId
            })
            // 监听连接成功
            this.client.on("connect", () => {
                uni.showToast({
                    title: "连接成功",
                    icon: "none"
                })
                this.connectBtnText = "连接成功"
                // 监听收到的信息
                this.client.on("message", (topic, payload) => {
                    uni.showToast({
                        title: `收到消息 - Topic: ${topic},Payload: ${payload}`,
                        icon: "none"
                    });
                    const currMsg = this.receivedMsg ? `<br />${payload}` : payload;
                    this.receivedMsg = this.receivedMsg.concat(currMsg)
                });
				// 监听错误
                this.client.on("error", (error) => {
                    this.connectBtnText = "连接"
                    console.log("onError", error);
                });
                this.client.on("close", () => {
                    this.connectBtnText = "连接"
                    console.log("close");
                });
                this.client.on("offline", () => {
                    this.connectBtnText = "连接"
                    console.log("offline");
                });
                // mqtt.js会自动断线重连
                this.client.on("reconnect", () => {
                    this.connectBtnText = "连接"
                    console.log("reconnecting...");
                });
            })
        } catch (err) {
            console.log(err)
            this.connectBtnText = "连接"
        }
    }
}

(3)断开连接

disconnectMqtt() {
    if(this.client.connected) {
        this.client.end(true)
        this.client = null
        this.connectBtnText = "连接"
        uni.showToast({
            title: "成功断开连接",
            icon: "none"
        })
        return
    }
    uni.showToast({
        title: `请先点击连接`,
        icon: "none"
    })
}

(4)订阅主题

subscribe() {
    if(this.client) {
        this.client.subscribe(this.subTopic, {qos: 2}, (err) => {
            if(!err) {
                uni.showToast({
                    title: `成功订阅主题:${this.subTopic}`,
                    icon: "none"
                }) 
            }
        })
        return
    }
    uni.showToast({
        title: `请先点击连接`,
        icon: "none"
    })
}

(5)取消订阅

unsubscribe() {
    if(this.client) {
        this.client.unsubscribe(this.subTopic, (err) => {
            if(!err) {
                uni.showToast({
                    title: `成功取消订阅主题:${this.subTopic}`,
                    icon: "none"
                })
            }
        })
        return
    }
    uni.showToast({
        title: `请先点击连接`,
        icon: "none"
    })
}

(6)发布

publish() {
    if(this.client) {
        this.client.publish(this.pubTopic, this.pubMsg, {qos: 2}, (err) => {
            if(!err) {
                console.log("发布信息成功",this.pubTopic, this.pubMsg)
            }
        })
        return
    }
    uni.showToast({
        title: `请先点击连接`,
        icon: "none"
    })
}

3.注意点

(1)微信小程序中需要将wss协议写为wxs

(2)如果连接使用的clientId是重复的话,会互相顶掉线

(3)消息级别:QoS 0 最多交付一次;QoS 1 至少交付一次;QoS 2 只交付一次;

(4)testtopic/#:指testtopic的任意子主题;testtopic/miniprogram:testtopic的miniprogram主题

(5)如果订阅和发布是同一个主题,那么发布信息的同时,也会接收到该信息。因此可以将订阅和发布定为不同的主题或采取其他方式进行识别

(6)如果连接公司的mqtt服务器出现问题的话,可以使用EMQX的免费公共MQTT服务器进行测试。有时候可能是服务器没有配置好,才导致连接不上

MQTT测试工具

可以使用MQTTX软件进行测试

1718446470587.png

微信图片_20240615180438.png

1718446686494.png

补充

上例中所用到的mqtt.js库有自动断线重连机制。但使用v4.1.0时发现,如果连接的设备被同一个clientId顶掉线,或者小程序退至后台再重新进入的话,mqtt重连的时间会很长,并且后续收到的所有主题的信息都会重复。
目前尝试的方案是使用v2.18.8,以及将自动重连改成手动重连。不知道大家有没有遇到过类似问题,如果有知道原因或者有其他方案的话,欢迎在评论区进行评论!!

参考链接

www.emqx.com/zh/blog/how…