基于 ESP-IDF 5.2.5 实现 ESP32-S3 的 MQTT 客户端的使用。
一、项目配置准备
1. 启用 MQTT 组件
在 ESP-IDF 中,MQTT 功能由 esp-mqtt
组件提供。需通过 menuconfig
启用相关功能:
idf.py menuconfig
- 导航至
Component config → ESP-MQTT
,确保以下选项启用:Enable MQTT over TCP
(默认启用,TCP 连接)- 若需 TLS 加密(MQTT over SSL),启用
Enable MQTT over SSL
,并根据需要配置证书(见下文)。
二、关键配置参数说明
以下是 MQTT 客户端常用配置参数(代码中通过 esp_mqtt_client_config_t
结构体设置):
参数 | 说明 |
---|---|
uri | MQTT 服务器地址(如 mqtt://broker.emqx.io:1883 或 mqtts://... ) |
client_id | 客户端 ID(可选,默认生成随机值) |
username /password | MQTT 服务器认证的用户名和密码(若服务器需要) |
keepalive | 心跳间隔(秒,默认 120) |
disable_clean_session | 是否保留会话(0 为清除会话,1 为保留) |
lwt_topic /lwt_msg | 遗嘱消息主题和内容(客户端异常断开时发送) |
transport | 传输协议(MQTT_TRANSPORT_OVER_TCP /MQTT_TRANSPORT_OVER_SSL ) |
三、测试代码
代码如下:
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "mqtt_client.h"
#include "nvs_flash.h"
#include "string.h"
static const char* TAG = "MQTT_Demo";
#define WIFI_SSID "esp32"
#define WIFI_PASSWORD "12345678"
#define MQTT_BROKER_URL "mqtt://broker-cn.emqx.io" //MQTT连接地址
#define MQTT_USERNAME "user" //MQTT用户名
#define MQTT_PASSWORD "12345678" //MQTT密码
#define MQTT_PUBLIC_TOPIC "/topic1" //测试用的,推送消息主题
#define MQTT_SUBSCRIBE_TOPIC "/topic2" //测试用的,需要订阅的主题
// MQTT 客户端句柄(全局变量,方便回调函数访问)
static esp_mqtt_client_handle_t mqtt_client = NULL;
// WiFi 连接事件处理
static void wifi_event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
{
esp_wifi_connect(); // WiFi 启动后尝试连接
}
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
{
ESP_LOGW(TAG, "WiFi 断开,尝试重连...");
esp_wifi_connect(); // 断开后自动重连
}
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
{
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
ESP_LOGI(TAG, "获取 IP: " IPSTR, IP2STR(&event->ip_info.ip));
// WiFi 连接成功后启动 MQTT
esp_mqtt_client_start(mqtt_client);
}
}
// MQTT 事件处理(核心回调函数)
static void mqtt_event_handler(void* handler_args, esp_event_base_t base,int32_t event_id, void* event_data)
{
esp_mqtt_event_handle_t event = event_data;
switch ((esp_mqtt_event_id_t)event_id)
{
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT 连接成功!");
// 连接成功后订阅主题(示例:订阅 MQTT_SUBSCRIBE_TOPIC)
int msg_id = esp_mqtt_client_subscribe(mqtt_client, MQTT_SUBSCRIBE_TOPIC, 1); // QoS=1
ESP_LOGI(TAG, "订阅主题,消息 ID: %d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGW(TAG, "MQTT 连接断开");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "订阅成功,消息 ID: %d", event->msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "取消订阅,消息 ID: %d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "消息发布成功,消息 ID: %d", event->msg_id);
break;
case MQTT_EVENT_DATA:
// 收到订阅的消息(打印主题和内容)
ESP_LOGI(TAG, "收到消息:");
ESP_LOGI(TAG, "主题: %.*s", event->topic_len, event->topic);
ESP_LOGI(TAG, "内容: %.*s", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGE(TAG, "MQTT 错误!");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
{
ESP_LOGE(TAG, "TCP 传输错误: 0x%x", event->error_handle->esp_tls_last_esp_err);
}
break;
default:
ESP_LOGI(TAG, "其他 MQTT 事件 ID: %d", event->event_id);
break;
}
}
// 初始化 WiFi
static void wifi_init(void)
{
ESP_ERROR_CHECK(esp_netif_init()); // 初始化网络接口
ESP_ERROR_CHECK(esp_event_loop_create_default()); // 创建默认事件循环
esp_netif_create_default_wifi_sta(); // 创建默认 STA 接口
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// 注册 WiFi 和 IP 事件回调
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,&wifi_event_handler, NULL, NULL));
// 配置 WiFi 参数(从 menuconfig 获取)
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASSWORD,
.threshold.authmode = WIFI_AUTH_WPA2_PSK, // 默认 WPA2
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
}
/*
client_id , // 可选,若不设置会自动生成随机 ID
keepalive = 60, // 心跳间隔 60 秒
disable_clean_session = 0, // 清除会话(断开后不保留状态)
lwt_topic = "topic/last_will", // 遗嘱主题(可选)
lwt_msg = "ESP32-S3 断开连接", // 遗嘱内容(可选)
lwt_qos = 1, // 遗嘱消息 QoS
lwt_retain = 1, // 遗嘱消息保留标志
*/
// 初始化 MQTT 客户端
static void mqtt_init(void)
{
// 配置 MQTT 参数
esp_mqtt_client_config_t mqtt_cfg =
{
.broker.address.uri = MQTT_BROKER_URL,
.broker.address.port = 1883,
.credentials.username=MQTT_USERNAME,
.credentials.authentication.password=MQTT_PASSWORD,
.credentials.client_id="ESP32-S3_MQTT_Client", // 可选,若不设置会自动生成随机 ID
.session.keepalive=120,// 心跳间隔 60 秒
.session.last_will.qos = 0, 遗嘱消息 QoS
};
// 创建 MQTT 客户端实例
mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
// 注册 MQTT 事件回调
ESP_ERROR_CHECK(esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID,mqtt_event_handler, NULL));
}
// 定时发布消息任务(示例:每 5 秒发布一次)
static void publish_task(void* arg)
{
int msg_count = 0;
while (1)
{
vTaskDelay(pdMS_TO_TICKS(5000)); // 5 秒间隔
if (mqtt_client == NULL)
{
continue;
}
// 构造消息内容(JSON 格式示例)
char payload[64];
snprintf(payload, sizeof(payload), "{\"count\": %d, \"device\": \"ESP32-S3\"}", msg_count++);
// 发布消息到 MQTT_PUBLIC_TOPIC,QoS=1,不保留
int msg_id = esp_mqtt_client_publish(mqtt_client, MQTT_PUBLIC_TOPIC, payload, 0, 1, 0);
ESP_LOGI(TAG, "发布消息,内容: %s,消息 ID: %d", payload, msg_id);
}
}
void app_main(void)
{
// 初始化 NVS(用于存储 WiFi 配置等)
ESP_ERROR_CHECK(nvs_flash_init());
// 初始化 WiFi 和 MQTT
wifi_init();
mqtt_init();
// 启动发布任务
xTaskCreate(publish_task, "publish_task", 4096, NULL, 5, NULL);
}
代码功能:
- WiFi 连接(自动重连)
- MQTT 客户端初始化(支持 TCP/TLS)
- 连接状态回调(连接成功/断开)
- 消息订阅与发布(订阅
topic/test
,每 5 秒发布一次消息)
四、代码关键功能说明
-
WiFi 连接:
- 通过
wifi_init()
初始化 WiFi,自动处理连接和重连。
- 通过
-
MQTT 客户端初始化:
mqtt_init()
配置 MQTT 服务器地址、认证信息等参数。- 支持遗嘱消息(LWT),客户端异常断开时通知服务器。
-
事件处理:
mqtt_event_handler
处理连接、断开、订阅、消息接收等事件。- 连接成功后自动订阅
topic/test
主题。
-
消息发布:
publish_task
任务每 5 秒向topic/test
主题发布 JSON 格式消息。
五、TLS 加密连接(可选)
若需 MQTT over SSL(如连接 mqtts://broker.emqx.io:8883
),需:
- 在
menuconfig
中启用Component config → ESP-MQTT → Enable MQTT over SSL
。 - 提供服务器证书(CA 证书),可通过以下方式嵌入代码:
- 将证书文件(如
broker_ca.pem
)放在项目的main
目录下。 - 在代码中添加证书内容(或通过
idf.py menuconfig
加载):// 在 mqtt_cfg 中添加证书配置 static const char* broker_ca_pem = "-----BEGIN CERTIFICATE-----\n" "MIICUTCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADBXMQswCQYDVQQGEwJDTjEL\n" "...(证书内容)...\n" "-----END CERTIFICATE-----\n"; esp_mqtt_client_config_t mqtt_cfg = { .uri = "mqtts://broker.emqx.io:8883", .cert_pem = broker_ca_pem, // CA 证书 // 其他参数... };
- 将证书文件(如
六、测试步骤
-
配置参数:
设置:WiFi SSID
: WiFi 名称WiFi Password
: WiFi 密码MQTT Broker URL
:测试用 MQTT 服务器(如mqtt://broker.emqx.io:1883
)
-
编译烧录:
idf.py set-target esp32s3 # 确保目标为 ESP32-S3 idf.py build flash monitor
-
验证日志:
- 观察串口日志,应看到 WiFi 连接成功、MQTT 连接成功、订阅成功的提示。
- 每 5 秒会打印“发布消息”日志,同时可通过 MQTT 客户端工具(如 MQTTX)订阅
topic/test
主题,验证消息接收。
注意事项
- MQTT 服务器选择:推荐使用公共测试服务器(如
broker.emqx.io
),无需认证。 - QoS 级别:示例中使用 QoS=1(确保消息至少送达一次),根据需求调整(0:最多一次,2:仅一次)。
- 重连机制:WiFi 或 MQTT 断开时会自动重连(依赖
esp_mqtt_client
内置逻辑)。 - 资源限制:ESP32-S3 的 RAM 有限,避免发布过大的消息(单条消息建议不超过 1KB)。
参考:
https://github.com/espressif/esp-idf/blob/master/examples/protocols/mqtt/tcp/main/app_main.c
https://docs.espressif.com/projects/esp-idf/zh_CN/v5.2.5/esp32/api-reference/index.html