esp32 基于 ESP-IDF 框架的 mqtt 客户端的实现

基于 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 结构体设置):

参数说明
uriMQTT 服务器地址(如 mqtt://broker.emqx.io:1883mqtts://...
client_id客户端 ID(可选,默认生成随机值)
username/passwordMQTT 服务器认证的用户名和密码(若服务器需要)
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 秒发布一次消息)

在这里插入图片描述

四、代码关键功能说明

  1. WiFi 连接

    • 通过 wifi_init() 初始化 WiFi,自动处理连接和重连。
  2. MQTT 客户端初始化

    • mqtt_init() 配置 MQTT 服务器地址、认证信息等参数。
    • 支持遗嘱消息(LWT),客户端异常断开时通知服务器。
  3. 事件处理

    • mqtt_event_handler 处理连接、断开、订阅、消息接收等事件。
    • 连接成功后自动订阅 topic/test 主题。
  4. 消息发布

    • publish_task 任务每 5 秒向 topic/test 主题发布 JSON 格式消息。

五、TLS 加密连接(可选)

若需 MQTT over SSL(如连接 mqtts://broker.emqx.io:8883),需:

  1. menuconfig 中启用 Component config → ESP-MQTT → Enable MQTT over SSL
  2. 提供服务器证书(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 证书
          // 其他参数...
      };
      

六、测试步骤

  1. 配置参数
    设置:

    • WiFi SSID: WiFi 名称
    • WiFi Password: WiFi 密码
    • MQTT Broker URL:测试用 MQTT 服务器(如 mqtt://broker.emqx.io:1883
  2. 编译烧录

    idf.py set-target esp32s3  # 确保目标为 ESP32-S3
    idf.py build flash monitor
    
  3. 验证日志

    • 观察串口日志,应看到 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值