MQTT TCP 示例

[English]

示例说明

本示例展示如何在 ESP32 上配置 MQTT 客户端,并通过 TCP 与 Broker 建立连接,演示连接状态管理及消息收发的基本操作。通过该示例,开发者可以学习 MQTT 客户端在 TCP 下的初始化流程及事件回调处理方法,为后续实现具体消息交互提供参考。

运行方法

示例完整代码见 mqtt tcp 示例。运行前需要配置 Wi-Fi 或以太网或 Thread,详见示例目录下的 README.md 文件。

备注

若示例运行后出现 esp-tls 错误,可通过查看 报错排查 文档查找对应原因和可能的解决办法。也可通过 ESP TLS 返回值 查找对应返回值。

通过以上方法,可发现若出现如下错误,其原因可能是连接超时。此时应检查网络是否通畅,例如可使用 MQTT 工具,如 MQTTX 访问此 MQTT Broker,或尝试更换 MQTT Broker 等。

E (15139) mqtt_example: Last error reported from esp-tls: 0x8006

头文件说明

本示例所使用的头文件涵盖了 FreeRTOS 任务管理、系统工具模块、蓝牙控制器与协议栈接口以及 BLE GATT 服务相关 API 等功能模块,构建了 BLE 初始化、Profile 管理、事件处理与数据交互的核心功能。

各头文件按功能分类如下:

  1. 标准 C 库功能:提供数据类型定义、内存管理、字符串操作和输入输出支持,用于底层数据处理和通用算法实现。

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
  1. 系统与硬件接口:提供 ESP32 系统控制和非易失性存储操作接口,用于芯片管理、复位、深度睡眠及存储配置参数。

#include "esp_system.h"
#include "nvs_flash.h"
  1. 网络与事件管理:提供网络接口初始化和事件循环机制,用于 TCP/IP 通信及事件驱动的系统响应。

#include "esp_event.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
  1. 日志与调试支持:提供统一的日志打印接口,支持模块标签和日志等级,用于开发和调试。

#include "esp_log.h"
  1. MQTT 客户端功能:提供 MQTT 客户端配置、连接建立、事件回调和消息收发接口,用于实现 IoT 设备与 Broker 的通信。

#include "mqtt_client.h"

任务函数说明

该示例包含了三个任务函数,分别用于 MQTT 客户端初始化、事件回调处理以及错误信息打印,帮助学习理解客户端的配置、连接及事件驱动通信逻辑。

MQTT 客户端初始化

mqtt_app_start() 用于初始化 MQTT 客户端并注册事件回调,准备客户端连接与消息处理。

其执行逻辑为:

  1. 配置结构体:具体结构体成员可参考 MQTT API,各结构体成员配置说明可参考 MQTT 结构体配置说明

  • 该示例中仅配置了 服务器地址uri

  • 因为完整 URI 已经包含了协议类型、主机名和端口信息,客户端会优先使用 URI 建立连接;同时,由于示例使用 TCP 明文传输,不涉及 TLS 加密或服务器验证,因此无需配置证书或验证参数,从而简化了客户端配置流程。

  1. 手动输入 URI:除使用默认 URI 外,也可选择通过标准输入获取 URI,该步骤仅在启用宏 CONFIG_BROKER_URL_FROM_STDIN 时执行。

  • 创建字符数组变量 line[],用于存储用户输入的 Broker URI,数组长度为 128。

  • 判断配置的 Broker 地址是否为 "FROM_STDIN",该标记表示当前不使用默认 URI,而是需要用户从标准输入提供实际 URI。

    • 从标准输入读取字符串并保存至变量 line,将结构体中的 uri 设置为该变量。

    • 打印确认信息,显示最终的 Broker URI。

  • 如果初始配置的 Broker 地址不是 "FROM_STDIN",则认为配置错误,打印错误日志并终止程序执行,避免在无效配置下继续运行。

  1. 初始化/启动 MQTT 客户端

  • 调用 esp_mqtt_client_init() 根据配置初始化 MQTT 客户端,并将返回的句柄保存至变量 client 供后续操作使用。API 介绍及参数说明可参考 MQTT API

  • 调用 esp_mqtt_client_register_event() 将事件回调函数注册到客户端,用于统一处理连接、订阅、收发消息等事件。API 介绍及参数说明可参考 MQTT API

  • 调用 esp_mqtt_client_start() 启动已初始化完成的 MQTT 客户端,与 Broker 建立连接并进入事件循环。API 介绍及参数说明可参考 MQTT API

事件回调函数

mqtt_event_handler() 是 MQTT 客户端事件回调函数,用于在客户端运行过程中集中处理各种事件,例如连接建立、断开、消息发布与订阅结果、消息接收及错误情况,从而实现客户端和 Broker 的交互逻辑。客户端可能触发的事件可参考 事件

其执行逻辑为:

  1. 打印调试信息,标记当前触发的事件来源和事件 ID。

  2. 将传入的事件数据和事件客户端转换为对应的类型。

  3. 创建整形变量 msg_id,用于后续接收发布或订阅操作的返回值。

  4. 通过事件 ID 区分事件类型,并针对不同事件执行对应操作:

  • MQTT_EVENT_CONNECTED

    • 打印事件类型。

    • 调用 esp_mqtt_client_publish() 发布一条消息到指定主题并打印结果,用于验证客户端连接后是否能正常发送数据。API 介绍及参数说明可参考 MQTT API

    • 两次调用 esp_mqtt_client_subscribe() 分别订阅同一主题不同 QoS 等级的消息,并打印结果,通过对比不同 QoS 的消息接收情况,可以验证客户端处理机制并判断 Broker 投递策略是否正常。API 介绍及参数说明可参考 MQTT API

    • 调用 esp_mqtt_client_unsubscribe() 取消订阅指定主题并打印结果,展示取消订阅流程,说明客户端可以动态调整订阅。API 介绍及参数说明可参考 MQTT API

备注

示例中立即取消订阅只是用于展示 API 调用顺序,实际使用中通常不会立即取消刚订阅的主题;对业务逻辑而言,应在收到相应的确认事件后再继续后续操作。

  • MQTT_EVENT_DISCONNECTED:打印日志以便定位断开连接的时间点。

  • MQTT_EVENT_SUBSCRIBED:打印事件类型后调用 esp_mqtt_client_publish() 发布一条消息以验证订阅结果。

  • MQTT_EVENT_UNSUBSCRIBED:打印日志以便定位取消订阅的时间点。

  • MQTT_EVENT_PUBLISHED:打印日志以便定位发布消息的时间点。

  • MQTT_EVENT_DATA:打印事件类型及接收到的主题和消息内容,用于消息处理和调试。

  • MQTT_EVENT_ERROR:对于 TCP 传输错误,调用任务函数 log_error_if_nonzero() 检查相关错误字段,便于定位问题。

  • 其他事件:打印事件 ID。

备注

事件处理逻辑可根据实际应用需求进行调整,此处示例仅用于演示客户端如何响应常见 MQTT 事件及调用发布、订阅、取消订阅等操作的基本流程。

错误信息打印

log_error_if_nonzero() 是一个辅助函数,用于检查传入的错误码 error_code,并在错误码非零时打印对应的错误信息 message,以便调试和排查问题。

主函数说明

该函数作为程序入口,用于完成系统初始化、网络配置以及 MQTT 客户端的启动与事件回调注册。

其执行流程为:

  1. 打印日志,程序启动信息、剩余堆内存以及使用的 ESP-IDF 版本。

  • 调用 esp_get_free_heap_size() 获取当前剩余堆内存。API 介绍及参数说明可参考 杂项系统 API

  • 调用 esp_get_idf_version() 获取 ESP-IDF 版本。API 介绍及参数说明可参考 杂项系统 API

  1. 调用 esp_log_level_set() 分别设置各个模块的日志等级,用于控制各模块输出的日志详细程度,包括 MQTT 客户端、示例程序、传输层和 TLS 等模块。API 介绍及参数说明可参考 日志库

  2. 调用 nvs_flash_init() 初始化 非易失性存储,为系统及 MQTT 客户端提供存储支持。API 介绍及参数说明可参考 NVS API

  3. 调用 esp_netif_init() 初始化网络接口层 ESP-NETIF,准备 Wi-Fi 或以太网功能。

  4. 调用 esp_event_loop_create_default() 创建默认 事件循环,为系统及 MQTT 客户端事件处理提供基础。API 介绍及参数说明可参考 事件循环库

  5. 调用 example_connect() 配置并连接网络(Wi-Fi 或以太网),确保设备具备联网能力。

  6. 调用任务函数 mqtt_app_start() 初始化并启动 MQTT 客户端,同时注册事件回调函数以处理连接、订阅、发布和接收消息等事件。