ESP32开发之路(9)—ESP32连接到MQTT服务器

ESP32开发之路(9)—ESP32实现MQTT通信

本次开发是在Ubuntu下的,使用的模块是GOOUUU-ESP32,使用VSCode编辑项目。代码使用来自esp-idf的例程。基于之前的工程:ESP32开发之路(7)—ESP32作为TCP客户端连接到局域网的PC机

一、连接到MQTT服务器

首先,要定义一个MQTT客户端配置结构体,最小配置即填入MQTT服务器的url即可,

    // 1、定义一个MQTT客户端配置结构体,输入MQTT的url
    esp_mqtt_client_config_t mqtt_cfg = {
        .uri = "mqtt://39.96.35.207",
    };

然后通过esp_mqtt_client_init获取一个MQTT客户端结构体指针,参数是MQTT客户端配置结构体

	// 2、通过esp_mqtt_client_init获取一个MQTT客户端结构体指针,参数是MQTT客户端配置结构体
    esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);

默认情况下,mqtt客户端使用事件循环库来发布相关的mqtt事件(已连接,已订阅,已发布等),所以我们要注册一个MQTT事件,填入MQTT事件处理函数,第一个参数为MQTT客户端结构体,第二个是事件ID对应的事件类型,第三个参数即事件处理函数,第四个参数为事件处理函数的参数

// 3、注册MQTT事件
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);

接下来就可以开启MQTT了

    // 4、开启MQTT功能
    esp_mqtt_client_start(client);

我们定义一个事件处理函数,打印一下事件类型:

// MQTT事件处理函数
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) 
{
    printf("Event dispatched from event loop base=%s, event_id=%d \n", base, event_id);
}

编译,烧录,运行,串口终端打印如下
在这里插入图片描述
图中所标识的三行都是MQTT事件所打印出来的信息。第一行表示从系统默认循环事件中发送来了MQTT事件,其ID为7,表示“客户端已初始化,即将开始连接到代理”;第二行说明MQTT发送了一个“CONNECT报文”,报文的含义是客户端请求连接服务端;第三行表示从系统默认循环事件中发送来了MQTT事件,其ID为1,表示“客户端已成功建立与代理的连接,客户端现在准备发送和接收数据”。
然后打开我们的EMQ控制台,在连接选项可以看到:
在这里插入图片描述
查阅ESP-IDF 编程指南可以知道,在我们对MQTT客户端配置结构体最小配置时,默认的客户端ID是ESP32_+十六进制格式的MAC地址的最后3个字节,可以看到,该连接的客户端ID符合,另外一位我们没有配置用户名,使用用户名处为未定义,然后默认的clean_session为true,即清楚会话为true,mqtt keepalive的默认值为120秒,和连接界面显示的心跳时间相同;
我们在MQTT客户端配置结构体中设置用户名为ESP32_GOOUUU
在这里插入图片描述
编译,烧录,运行,可以看到,连接界面的用户名也相应的改变了
在这里插入图片描述

二、通过MQTT发布和订阅消息

我们在MQTT事件处理函数处理有关MQTT的事件,首先,获取MQTT客户端结构体指针

    // 获取MQTT客户端结构体指针
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;

然后通过事件ID来分别处理对应的事件,首先,连接成功事件,连接成功后,我们订阅一个主题,发布一个主题,

    // 通过事件ID来分别处理对应的事件
    switch (event->event_id) 
    {
        // 建立连接成功
        case MQTT_EVENT_CONNECTED:
            printf("MQTT_client cnnnect to EMQ ok. \n");
            // 发布主题,主题消息为“I am ESP32.”,自动计算有效载荷,qos=0
            ret = esp_mqtt_client_publish(client, "ESP32_Publish", "I am ESP32.", 0, 0, 0);
            if(ret != -1)
                printf("mqtt publish ok. ret = %d \n",ret);
            // 订阅主题,qos=0
            esp_mqtt_client_subscribe(client, "ESP32_Subscribe", 0);
            if(ret != -1)
                printf("mqtt subscribe ok. ret = %d \n",ret);
            
            break;
        default:break;
    }

然后还有其他事件的处理也添加进去

		// 客户端断开连接
        case MQTT_EVENT_DISCONNECTED:
            printf("MQTT_client have disconnected. \n");
            break;
        // 主题订阅成功
        case MQTT_EVENT_SUBSCRIBED:
            printf("mqtt subscribe ok. msg_id = %d \n",event->msg_id);
            break;
        // 取消订阅
        case MQTT_EVENT_UNSUBSCRIBED:
            printf("mqtt unsubscribe ok. msg_id = %d \n",event->msg_id);
            break;
        //  主题发布成功
        case MQTT_EVENT_PUBLISHED:
            printf("mqtt published ok. msg_id = %d \n",event->msg_id);
            break;
        // 已收到订阅的主题消息
        case MQTT_EVENT_DATA:
            printf("mqtt received topic: %.*s \n",event->topic_len, event->topic);
            printf("topic data: %.*s\r\n", event->data_len, event->data);
            break;
        // 客户端遇到错误
        case MQTT_EVENT_ERROR:
            printf("MQTT_EVENT_ERROR \n");
            break;
        default:
            printf("Other event id:%d \n", event->event_id);
            break;

编译,烧录,运行,可以看到,连接成功,主题发布成功,主题订阅成功
ESP32开发之路(9)—ESP32连接到MQTT服务器_第1张图片
我们打开MQTTfx可以收到主题的消息:
ESP32开发之路(9)—ESP32连接到MQTT服务器_第2张图片
然后通过在MQTTfx发布一个主题消息,可以看到,ESP32接受主题和主题消息:
ESP32开发之路(9)—ESP32连接到MQTT服务器_第3张图片

三、代码

#include 
#include 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "driver/gpio.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"

#include "mqtt_client.h"

static const char *TAG = "MQTT_EXAMPLE";

#define GPIO_LED_NUM 2                      /* LED引脚编号 */

/* wifi连接函数,位于app_wifi.c,阻塞状态 */
void wifi_connect_init(void);

// 事件处理函数
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) 
{
    //printf("Event dispatched from event loop base=%s, event_id=%d \n", base, event_id);
    // 获取MQTT客户端结构体指针
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;
    // 通过事件ID来分别处理对应的事件
    switch (event->event_id) 
    {
        // 建立连接成功
        case MQTT_EVENT_CONNECTED:
            printf("MQTT_client cnnnect to EMQ ok. \n");
            // 发布主题,主题消息为“I am ESP32.”,自动计算有效载荷,qos=1
            esp_mqtt_client_publish(client, "ESP32_Publish", "I am ESP32.", 0, 1, 0);
            // 订阅主题,qos=0
            esp_mqtt_client_subscribe(client, "ESP32_Subscribe", 0);           
            break;
        // 客户端断开连接
        case MQTT_EVENT_DISCONNECTED:
            printf("MQTT_client have disconnected. \n");
            break;
        // 主题订阅成功
        case MQTT_EVENT_SUBSCRIBED:
            printf("mqtt subscribe ok. msg_id = %d \n",event->msg_id);
            break;
        // 取消订阅
        case MQTT_EVENT_UNSUBSCRIBED:
            printf("mqtt unsubscribe ok. msg_id = %d \n",event->msg_id);
            break;
        //  主题发布成功
        case MQTT_EVENT_PUBLISHED:
            printf("mqtt published ok. msg_id = %d \n",event->msg_id);
            break;
        // 已收到订阅的主题消息
        case MQTT_EVENT_DATA:
            printf("mqtt received topic: %.*s \n",event->topic_len, event->topic);
            printf("topic data: %.*s\r\n", event->data_len, event->data);
            break;
        // 客户端遇到错误
        case MQTT_EVENT_ERROR:
            printf("MQTT_EVENT_ERROR \n");
            break;
        default:
            printf("Other event id:%d \n", event->event_id);
            break;
    }
}

static void mqtt_app_start(void)
{
    // 1、定义一个MQTT客户端配置结构体,输入MQTT的url
    esp_mqtt_client_config_t mqtt_cfg = {
        .uri = "mqtt://39.96.35.207",
        .username = "ESP32_GOOUUU"
    };

    // 2、通过esp_mqtt_client_init获取一个MQTT客户端结构体指针,参数是MQTT客户端配置结构体
    esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);

    // 3、注册MQTT事件
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);

    // 4、开启MQTT功能
    esp_mqtt_client_start(client);
}


void app_main(void)
{
    /* 打印Hello world! */
    printf("Hello world!\n");

    wifi_connect_init();

    mqtt_app_start();

    while(1)
    {
        gpio_set_level(GPIO_LED_NUM, 0);        /* 熄灭 */
        vTaskDelay(500 / portTICK_PERIOD_MS);   /* 延时500ms*/
        gpio_set_level(GPIO_LED_NUM, 1);        /* 点亮 */
        vTaskDelay(500 / portTICK_PERIOD_MS);   /* 延时500ms*/
    }
}

你可能感兴趣的:(ESP32)