MQTT介绍

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅publish/subscribe)模式的“轻量级”通讯协议。

MQTT最大优点在于,用极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。

作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

在这里笔者不打算做原理性的介绍,而是直接进行演示MQTT的使用过程。

MQTT 服务器

在生产环境中,正常是需要部署MQTT服务器的(或者是使用云服务器厂商的物联网平台)。笔者只是进行短暂的测试,所以使用免费的在线 MQTT 服务器。

EMQ的免费服务器为 2 个节点的 EMQX 企业版集群,部署在上海腾讯云。

EMQ 提供了通俗易懂的技术文章,帮助开发者快速了解 MQTT 协议及其相关特性。

参考EMQ的使用手册,笔者了解到进行测试需要MQTT 服务器信息。

当然,EMQ提供了MQTT客户端工具(用于快速连接和测试 MQTT 服务与应用),可以用来快速测试MQTT服务器的可用性。

在这里,笔者演示使用online-mqtt-client。步骤如下。

  1. 进入MQTT客户端工具,界面如下。 image-20230404161433686

  2. 参考公共MQTT服务器地址,新建连接。

    image-20230404161545034

  3. 连接成功,可以看到绿色的提示符。

    image-20230404161728710

  4. 输入订阅的主题,发送数据。

    image-20230404161826299

  5. 如果此时没有订阅该主题,是无法接收到数据的,这个时候可以在客户端添加订阅进行测试(或者通过代码对该主题进行订阅)。

    image-20230404162707094

  6. 发送数据,得到反馈,测试成功。

    image-20230404162655388

PC端MQTT测试

参考文档如何在 Python 中使用 MQTT | EMQ (emqx.com)进行测试,参考文档十分详细,因此笔者只提供publish、subscribe的两个文件的代码。

publish.py(代码用于实现向/python/mqtt主题发送消息,消息内容是计数值1、2、3······)

import random
import time

from paho.mqtt import client as mqtt_client

broker = 'broker-cn.emqx.io'
port = 1883
topic = "/python/mqtt"
# generate client ID with pub prefix randomly
client_id = f'python-mqtt-{random.randint(0, 1000)}'


def connect_mqtt():
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client


def publish(client):
    msg_count = 0
    while True:
        time.sleep(1)
        msg = f"messages:" + str(msg_count)
        result = client.publish(topic, msg)
        # result: [0, 1]
        status = result[0]
        if status == 0:
            print(f"Send `{msg}` to topic `{topic}`")
        else:
            print(f"Failed to send message to topic {topic}")
        msg_count += 1


def run():
    client = connect_mqtt()
    client.loop_start()
    publish(client)


if __name__ == '__main__':
    run()

subscribe.py(代码功能为mqtt消息的订阅,当消息发布之后打印至控制台)

import random

from paho.mqtt import client as mqtt_client

broker = 'broker-cn.emqx.io'
port = 1883
topic = "/python/mqtt"
# generate client ID with pub prefix randomly
client_id = f'python-mqtt-{random.randint(0, 1000)}'


def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client


def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        print(f"Received `{msg.payload}` from `{msg.topic}` topic")

    client.subscribe(topic)
    client.on_message = on_message


def run():
    client = connect_mqtt()
    subscribe(client)
    client.loop_forever()


if __name__ == '__main__':
    run()

运行以上两端代码,测试结果如下。

image-20230404155420433

这里表明作为发布者,正在发布数据包messages:x,其中x是一个计数值。

image-20230404155625967

这里可以看到订阅者可以接收到数据包,测试成功。

ESP32端MQTT测试

刚才通过PC端演示了MQTT的通信过程,其实并不能体现MQTT在嵌入式通信的实用性。所以笔者在ESP32端进行演示。

首先介绍一下MicroPython。MicroPython和Python编程语言一样,在任何板子上都可以使用通用的API控制硬件底层,比如点亮 LED 灯,读取传感器信息, LCD 显示字符串、控制电机、连接网络、连接蓝牙等等。

因此,笔者参考MQTT快速上手进行测试,利用MQTT客户端工具发布消息为My name is LIN!,效果如下。

image-20230404204456914

我的想法

笔者通过PC端以及嵌入式端进行了MQTT的通信测试。演示的结果可以表明,通过MQTT协议,可以进行广域网下的设备通信。

实际上,可以通过ESP32+MQTT实现远程的电脑开机棒(不同于WOL网络唤醒),即通过esp32短接电脑主板对应端子实现远程电脑开机。

参考资料

https://zhuanlan.zhihu.com/p/421109780

https://post.smzdm.com/p/a5kq0or7/

https://www.emqx.com/zh/mqtt

https://doc.itprojects.cn/0006.zhishi.esp32/02.doc/index.html#/c05.mqtt

https://zhuanlan.zhihu.com/p/73137316