MQTT

[English]


如何使用 MQTT 配置服务器地址为自主云平台?

可以参考 MQTT 例程


使用 ESP8266 release/v3.3 版本的 SDK 测试 examples/protocols/esp-mqtt/tcp 例程,配置 Wi-Fi 账号、密码,连接默认配置的服务器,出现连接失败,log 如下,是什么原因?

W (4211) MQTT_CLIENT: Connection refused, not authorized
I (4217) MQTT_CLIENT: Error MQTT Connected
I (4222) MQTT_CLIENT: Reconnect after 10000 ms
I (4228) MQTT_EXAMPLE: MQTT_EVENT_DISCONNECTED
I (19361) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000

当出现如上报错,表示服务器拒绝了连接,原因是客户端错误的 MQTT 用户名和密码导致服务端认证没有通过。建议您确认是否使用了正确的 MQTT 用户名和密码。


ESP-IDF 中 MQTT 组件 keepalive 的默认值是多少?

默认值为 120 s,在 mqtt_config.h 中通过 MQTT_KEEPALIVE_TICK 定义。


MQTT 支持自动重连吗?

  • MQTT 的自动重连由 esp_mqtt_client_config_t 中的成员变量 disable_auto_reconnect 控制,该变量值默认为 false,表示使能自动重连。

  • 可以使用 reconnect_timeout_ms 设置重连超时时间。


ESP-IDF 支持的 MQTT 版本有哪些?

ESP-IDF 目前支持的 MQTT 版本为 MQTT 3.1,MQTT 3.1.1 和 MQTT 5.0。


ESP-IDF 里 Wi-Fi 连接断开的时候,之前 MQTT 上层协议申请的内存会自动释放吗?

  • 不会自动释放,但对于用户而言不需要关心这部分内存。用户要关心的是 ESP 给用户封装的应用层。

  • 对于 MQTT 应用层组件,用户初始化 MQTT 的时候会获得一个 MQTT 句柄,用户只需关心这个句柄里的内存,在不用 MQTT 的时候调用 stop 或者 destroy 释放对应 MQTT 内存即可。对于 Wi-Fi 断开与连接,用户也不需要通过 stop 或者 destroy 释放这个 MQTT 句柄然后再重新申请 MQTT 句柄。因为 MQTT 组件里有自动重连机制。


ESP32-C3 MQTT 是否能不设置对应的 client_id 而将 client_id 默认配置为空字符串?

  • 可以,可通过在应用代码里设置 set_null_client_idtrue 来实现。


使用 ESP-IDF MQTT 客户端发布 QoS 为 1 或者 2 的数据后,当 MQTT_EVENT_PUBLISHED 触发时是否意味着已经收到了对端合适的 ack 来证明这次发布已完成?还是仅仅只能说明成功发送了一次数据给服务器?

MQTT_EVENT_PUBLISHED 事件触发代表代理已确认收到客户端的发布的 QoS 为 1 或者 2 的消息,证明这次发布已经顺利完成。


ESP MQTT 客户端断开连接后,如何手动释放 MQTT 资源?

手动调用 esp_mqtt_client_destroy API 即可。


ESP32 Wi-Fi 和低功耗蓝牙共存时,MQTT keepalive 时间该如何配置?有没有什么合适的配置时间?

  • 在 ESP32 中使用 Wi-Fi 和低功耗蓝牙共存时,应该合理配置 MQTT keepalive 时间。由于 Wi-Fi 和低功耗蓝牙都需要消耗系统资源,因此如果 keepalive 时间设置得太短,可能会导致系统负载过高,影响系统稳定性和性能。

  • 通常情况下,建议根据实际情况设置 MQTT keepalive 时间,以确保设备在线的同时,尽可能减少系统资源的消耗。在 Wi-Fi 和低功耗蓝牙共存的情况下,可以考虑将 MQTT keepalive 时间设置为较长的时间,如可以配置为 30 s、60 s 等,这样可以减少设备与 MQTT broker 之间的通信次数,降低系统负载。

  • 需要注意的是,如果 keepalive 时间设置得太长,当设备掉线时,可能需要等待较长时间才能发现设备离线,这可能会影响实时性和可靠性。因此,需要根据实际需求和系统性能来合理设置 MQTT keepalive 时间。


ESP MQTT 客户端的 disconnect 事件消息什么时候才会触发?

disconnect 消息只有在以下情况出现:

  • MQTT 建立连接时,TCP 连接错误

  • MQTT 建立连接时,MQTT 连接错误

  • 自行主动调用了 disconnect 函数

  • 接收或发送数据异常

  • 规定时间内没收到对端 MQTT PING RESPONSE

  • 发送 MQTT PING 请求失败

  • 重新连接


ESP32 MQTT 客户端与服务器断开后会自动尝试重新连接吗?

ESP MQTT 客户端里的 esp_mqtt_client_config_t 结构体配置里有 disable_auto_reconnect 参数,可以通过配置这个参数为 true 或者 false 来决定是否需要 MQTT 自动重连,MQTT 默认会自动进行重连。


如何检测 ESP32 是否已经与 MQTT 服务器断开?

检测 ESP32 是否已经与服务器断开可以使用 MQTT 的 PING 机制。也就是配置 ESP-MQTT 中 esp_mqtt_client_config_t 结构体里的 keepalive 参数 disable_keepalivekeepalive,比如将 disable_keepalive 配置为 false (默认参数也是 false,即默认开启 keepalive 机制),然后配置 keepalive 参数为 120 s 来设置保活时间,默认为 120 s。这样 MQTT 客户端会定期发送 PING 来检测和 MQTT 服务器的连接是否正常。


在连接 MQTT 服务器时遇到连接失败的情况,如何获取具体的错误原因并排查问题?

MQTT 连接失败时可以在 MQTT 事件 MQTT_EVENT_ERROR 里解析结构体 esp_mqtt_error_codes_t 中的数据,详情请参考示例中的 MQTT_EVENT_ERROR 事件。


如何调整 MQTT 的遗嘱消息发送时间?

可以通过缩短 MQTT 心跳时间来减少遗嘱消息的发送延迟。


MQTT 客户端在发送数据时遇到超时,如何确定问题出现在哪个网络层?

可以通过抓包分析来确定问题所在层,检查是在传输层、网络层还是数据链路层出现问题。具体失败环节可能是服务器未返回 ACK、服务器返回了 ACK 但 Wi-Fi 没有收到,或者数据包未成功发送。


为什么 MQTT 客户端在网络状况良好时仍然报告写入超时?

可能因为底层 LWIP 缓冲区已满,导致无法写入。这通常是由于缓冲区里的包没有收到对端的 ACK。具体原因可能包括服务器没有发送 ACK、服务器发送了 ACK 但 Wi-Fi 没有收到,或者数据包没有成功发出。


在使用 MQTT 通信时,为什么会出现内存骤降的情况?

MQTT 中的 outbox 会占用内存,对于 QoS 大于 0 的消息,只有在对端发送 MQTT 层的 ACK 后,相关内存才会被释放。可以通过配置 CONFIG_HEAP_USE_HOOKS 来跟踪内存的分配和释放情况。