本次开发是在Ubuntu下的,使用的模块是GOOUUU-ESP32,使用VSCode编辑项目。代码使用来自esp-idf的例程。基于之前的工程:ESP32开发之路(7)—ESP32作为TCP客户端连接到局域网的PC机
首先,要定义一个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客户端结构体指针
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;
编译,烧录,运行,可以看到,连接成功,主题发布成功,主题订阅成功
我们打开MQTTfx可以收到主题的消息:
然后通过在MQTTfx发布一个主题消息,可以看到,ESP32接受主题和主题消息:
#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*/
}
}