MQTT介绍
MQTT(Message Queuing Telemetry Transport)是一种轻量级的消息协议,旨在设备之间进行通信,尤其是在网络条件较差的情况下。MQTT v3.1.1 和 MQTT v5 是该协议的两个主要版本。
MQTT v3.1.1:
- 优点:
- 成熟和广泛支持:作为较早的版本,v3.1.1 得到了广泛的实现和支持,包括各种客户端库和服务器(代理)。
- 稳定性:由于长时间的使用,v3.1.1 版本的稳定性和可靠性得到了验证。
- 资源消耗低:设计上考虑了低带宽和低功耗设备,因此非常适合物联网(IoT)应用。
- 缺点:
- 功能限制:与 v5 相比,v3.1.1 缺少一些高级功能,如消息的精确一次性传递(Exactly-Once Delivery)和用户属性(User Properties)。
- 可扩展性:v3.1.1 的一些限制可能使得在某些高级场景下的使用受到限制。
MQTT v5:
- 优点:
- 增强的功能:v5 引入了许多新特性,包括消息的精确一次性传递、用户属性、共享订阅(Shared Subscriptions)、动态消息过滤(Dynamic Message Filters)等,这些特性提高了协议的灵活性和可扩展性。
- 更好的错误处理:v5 提供了更详细的错误代码,有助于客户端更好地理解和处理错误情况。
- 改进的会话恢复:v5 改进了会话恢复机制,使得客户端可以在断开连接后更快地恢复状态。
- 缺点:
- 兼容性问题:由于是较新的版本,v5 的支持可能不如 v3.1.1 广泛,这可能导致与旧系统或客户端的不兼容问题。
- 实现复杂性:新特性的引入可能增加了实现的复杂性,对于资源受限的设备来说,这可能是一个挑战。
总的来说,MQTT v3.1.1 由于其成熟度和广泛支持,仍然是许多应用的首选。而 MQTT v5 提供了更多的高级功能和更好的错误处理,适合需要这些特性的新应用。选择哪个版本取决于具体的应用需求、资源限制以及对新特性的需求。随着时间的推移,v5 的支持和采用可能会增加,从而减少兼容性问题。
mqtt服务器软件Mosquitto
当前比较流行的mqtt服务器是:Mosquitto、EMQTT、HiveMQ等,经过短暂的了解,最终决定使用Mosquitto。
FreeBSD下安装
pkg install mosquitto
安装好后提示:
Message from mosquitto-2.0.18:
The mosquitto MQTT Python driver is now provided by net/py-paho-mqtt
FreeBSD下启动服务,若没有写入rc.conf文件,则启动时需要加上onestart
sudo service mosquitto start
sudo service mosquitto onestart
Ubuntu下安装
安装服务器
sudo apt install mosquitto
安装客户端
sudo apt install mosquitto-clients
启动并配置服务
以Ubuntu下为例。
启动服务
可以使用service启动服务:
sudo service mosquitto start
当然一开始不知道,直接使用运行mosquitto命令启动了服务:
mosquitto
1731855204: Warning: Unable to drop privileges to 'mosquitto' because this user does not exist. Trying 'nobody' instead.
1731855204: mosquitto version 2.0.18 starting
1731855204: Using default config.
1731855204: Starting in local only mode. Connections will only be possible from clients running on this machine.
1731855204: Create a configuration file which defines a listener to allow remote access.
1731855204: For more details see https://mosquitto.org/documentation/authentication-methods/
1731855204: Opening ipv4 listen socket on port 1883.
1731855204: Opening ipv6 listen socket on port 1883.
1731855204: mosquitto version 2.0.18 running
后来才知道可以用service启动和停止服务
后来发现端口只绑定了本地ip,要绑定0.0.0.0,则需要修改配置。
客户端测试:
首先在服务器本机测试
执行mosquitto_sub客户端侦听服务:
mosquitto_sub -t "mytopic"
执行mosquitto_pub发布信息
另一个终端执行:
mosquitto_pub -t "mytopic" -m "Hello, MQTT!!"
1731855866: New connection from 127.0.0.1:29987 on port 1883.
1731855866: New client connected from 127.0.0.1:29987 as auto-E0721C4C-5B09-EF6C-E3B3-892DBEDC9C05 (p2, c1, k60).
1731855866: Client auto-E0721C4C-5B09-EF6C-E3B3-892DBEDC9C05 disconnected.
就会发现刚才的信息Hello, MQTT!!被侦听端收到了:
mosquitto_sub -t "mytopic"
Hello, MQTT!!
发送消息的详细命令:
mosquitto_pub -t "mytopic" -m "Hello, MQTTexitlast1" -h "192.168.0.13"
设置了用户验证后,就需要带用户名和口令参数,比如
mosquitto_pub -t "mytopic" -m "Hello, MQTT!!" -h 192.168.0.13 -u ral -P ral
修改mosquitto配置
添加用户
在/etc/mosquitto目录下修改配置文件,修改mosquitto.conf文件,加入这样两句:
allow_anonymous false
password_file /etc/mosquitto/passwd
执行mosquitto_passwd创建用户ral并写入/etc/mosquitto/passwd文件:
sudo mosquitto_passwd -c /etc/mosquitto/passwd ral
Password:
Reenter password:
这样发送和接收信息都需要用户验证。
修改绑定服务到0.0.0.0
在/etc/mosquitto/conf.d目录里创建bindip.conf文件,加入这一句:
bind_address 0.0.0.0
这样服务就能监听0.0.0.0 ,也就是其它非本机也可以连它。
如果原来ufw防火墙没有放开,那么需要放开1883端口:
sudo ufw allow 1883
这时候再测试一下信息:
mosquitto_pub -t 'mytopic' -m 'ehllo' -u 'ral' -P 'ral'
客户端应该能接收到信息:
mosquitto_sub -t "mytopic"
Hello, MQTT!!
重启mosquitto服务
每次修改mosquitto配置后,都要重启服务
sudo service mosquitto restart
带用户验证的测试
消息接收:
# 带上用户验证
mosquitto_sub -t "mytopic" -u 'ral' -P 'ral'
# 或是带上地址
mosquitto_sub -t "mytopic" -u 'ral' -P 'ral' -h '192.168.0.13'
消息发送:
# 带用户验证的消息发送
mosquitto_pub -t 'mytopic' -m 'hello world' -u 'ral' -P 'ral'
# 带上服务器ip地址
mosquitto_pub -t 'mytopic' -m 'hello world2' -u 'ral' -P 'ral' -h '192.168.0.13'
接收端接收到信息:
mosquitto_sub -t "mytopic" -u 'ral' -P 'ral' -h '192.168.0.13'
hello world
证明配置设置的正确,服务器一切正常!
esp32c3开发板配置
esp32c3开发板烧录micropython 交互环境,参见:esp32c3安装micropython环境-CSDN博客
烧录好固件,启动开发板,进入micropython交互环境。参见:esp32-c3开发板开箱第一步:连上usb口看log信息-CSDN博客
开发板启动wifi连上网
交互界面里执行下面代码连wifi,注意wifi的名字和密码需要根据实际情况修改:
import network
import time
nic = network.WLAN(network.STA_IF)
nic.active(True)
# nic.scan()
if not nic.isconnected():nic.connect("wifi名字", "wifi密码")print("Waiting for connection...")while not nic.isconnected():time.sleep(1)print(nic.ipconfig("addr4"))
如果能输出网络信息,那么就证明连上了wifi
>>> print(nic.ipconfig("addr4"))
('192.168.0.104', '255.255.255.0')
开发板接收mqtt消息代码
继续执行esp32c3开发板里的micropython代码:
from umqtt.simple import MQTTClient# 定义 MQTT 代理的地址和端口
SERVER = "192.168.0.13"
PORT = 1883# 定义客户端 ID、用户名和密码
CLIENT_ID = "my_client_id"
USERNAME = "ral"
PASSWORD = "ral"# 定义要订阅的主题
TOPIC = b"mytopic"# 创建 MQTTClient 实例,并传递用户名和密码参数
client = MQTTClient(CLIENT_ID, SERVER, PORT, user=USERNAME, password=PASSWORD)# 连接到 MQTT 代理
client.connect()# 订阅主题
client.subscribe(TOPIC)# 定义消息回调函数
def sub_cb(topic, msg):print("Received message: ", msg)# 设置消息回调函数
client.set_callback(sub_cb)# 进入消息循环
while True:client.wait_msg()
中文会占用输入缓冲区大小,有点干扰输入,所以可以黏贴下面去掉中文注释的代码:
from umqtt.simple import MQTTClientSERVER = "192.168.0.13"
PORT = 1883CLIENT_ID = "my_client_id"
USERNAME = "ral"
PASSWORD = "ral"TOPIC = b"mytopic"client = MQTTClient(CLIENT_ID, SERVER, PORT, user=USERNAME, password=PASSWORD)client.connect()def sub_cb(topic, msg):print("Received message: ", msg)client.set_callback(sub_cb)client.subscribe(TOPIC)while True:client.wait_msg()
不要一次黏贴一大段,可以2-3句黏贴,比如像这句:client = MQTTClient(CLIENT_ID, SERVER, PORT, user=USERNAME, password=PASSWORD) 比较长,就单独黏贴。
开发板运行后,用一个客户端发送消息
# 本机
mosquitto_pub -t 'mytopic' -m 'hello world' -u 'ral' -P 'ral'
# 非本机
mosquitto_pub -t 'mytopic' -m 'hello world2' -u 'ral' -P 'ral' -h '192.168.0.13'
这时候开发板交互界面里就能接收到发送的信息了!
>>> while True:
... client.wait_msg()
...
Received message: b'hello'
48
这样我们这次实践就完成了!
总结
总体是一次非常愉快的esp32c3开发板与mqtt服务器通信的实践操作。但是由于是第一次使用mosquitto,对它的配置不熟悉,同时也是第一次使用micropython里的mqtt模块(umqtt)进行通信,对它也不熟悉,所以这次实践中箭走了很多弯路,碰到很多问题,幸运的是都解决了。
mqtt服务器,用了半天时间选型为mosquitto,大约这就是眼缘吧,毕竟它是eclicps旗下的,而且FreeBSD还有它的pkg包。安装mosquitto后,需要修改其配置,比如添加用户和密码到指定的文件,修改绑定ip到0.0.0.0,在Ubuntu服务器ufw防火墙中放开1883端口。
esp32c3开发板这块,首先需要烧micropython交互环境的固件,然后usb串口登录到micropython的交互界面,输入python代码。先要配置好WiFi启动tcp/ip网络,然后就是调用umqtt模块进行侦听mqtt消息。micropython的缓冲区较小,不能像普通python里面那样一下子可以黏贴太长的代码段,这也需要注意。
调试
esp32c3上mqtt连接失败
其实这是一个大问题,后来是分解成几个小问题一一解决的。
>>> mqtt_client = connect_mqtt()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in connect_mqtt
File "umqtt/simple.py", line 66, in connect
OSError: [Errno 104] ECONNRESET
想起来了,原来是mqtt服务器跨了网段,为了简化测试,后来就用了linux客户端mosquitto_pub和mosquitto_sub -t "mytopic" 先进行测试。(其实esp32的网络模块是可以联网、跨网段通信的)
在同一网段开服务器,还是不行
原来是ufw防火墙没有放开,放开1883端口
sudo ufw allow 1883
发现没有绑定0.0.0.0,修改配置文件/etc/mosquitto/conf.d/bindip.conf,加入这句:
bind_address 0.0.0.0
然后重启服务
sudo service mosquitto restart
用客户端mosquitto_pub再测试有如下报错:
发送信息报错Connection Refused: not authorised.
mosquitto_pub -t "mytopic" -m "Hello, MQTTexitlast1" -h "192.168.0.13"
Connection error: Connection Refused: not authorised.
添加用户:
sudo mosquitto_passwd -c /etc/mosquitto/passwd ral
Password:
Reenter password:
在/etc/mosquitto目录下的mosquitto.conf文件中加入信息:
allow_anonymous false
password_file /etc/mosquitto/passwd
重启服务后测试:
mosquitto_pub -t "mytopic" -m "Hello, MQTT!!" -h 192.168.0.13 -u ral -P ral
终于不报用户验证错了,现在报错:
esp32连mosquitto报错 Subscribe callback is not set
>>> client.subscribe(TOPIC)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "umqtt/simple.py", line 152, in subscribe
AssertionError: Subscribe callback is not set
是那段代码又问题,换代码:
from umqtt.simple import MQTTClientSERVER = "mqtt.eclipse.org"
PORT = 1883CLIENT_ID = "my_client_id"
USERNAME = "my_username"
PASSWORD = "my_password"TOPIC = b"test/topic"SERVER = "192.168.0.13"
PORT = 1883CLIENT_ID = "my_client_id"
USERNAME = "ral"
PASSWORD = "ral"TOPIC = b"mytopic"client = MQTTClient(CLIENT_ID, SERVER, PORT, user=USERNAME, password=PASSWORD)client.connect()def sub_cb(topic, msg):print("Received message: ", msg)client.set_callback(sub_cb)client.subscribe(TOPIC)while True:client.wait_msg()
这个代码就ok了!
esp32 micropython里黏贴python代码有时候会出错
发现黏贴代码到后面就乱了,估计是黏贴长度超限导致的,减少黏贴长度,问题解决。