摘要:实现方法介绍。 实现协议需要客户端和服务器之间的通信。 在通信过程中,协议中存在三个身份:发布者、代理服务器、订阅者。 消息发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
1. MQTT 概述 1.1 实现
MQTT 协议的实现需要客户端和服务器之间进行通信。 在通信过程中,MQTT协议中存在三种身份:发布者(publisher)、代理(broker)(服务器)、订阅者(subscriber)。 消息发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
MQTT发送的消息分为两部分:主题和负载。
主题可以理解为一种消息。 当订阅者订阅时,他们会收到主题的消息内容(有效负载)。
Payload可以理解为消息的内容,指向订阅者想要消费的具体内容。
MQTT 服务器的主要工作是传递数据;它没有存储数据的能力。 你可以订阅你发布的主题,服务器是回发测试。 使用 MQTT,订阅所需的逻辑更加清晰。 采用标准化流程可以摆脱开发、实施、调试和测试私有协议的复杂过程。 1.2 ESP-MQTT
ESP-MQTT 是 MQTT 协议客户端的实现(MQTT 是轻量级发布/订阅消息协议)。
支持 TCP 上的 MQTT、带 mbedtls 的 SSL、Websocket 上的 MQTT、Websocket 安全上的 MQTT。 使用UR轻松设置多个实例(一个应用程序中的多个客户端),支持订阅、发布、身份验证、遗嘱消息、保活 ping 和所有三个 QoS 级别(需要功能齐全的客户端)。
ESP-IDF 编程指南 - ESP-MQTT
2. API 说明
以下 MQTT 客户端接口位于 Components/mqtt/esp-mqtt/include/mqtt_client.h它位于 。
2.1 ESP_MQT_CLIENT_INIT
2.2 ESP_MQTT_CLIENT_REGINT_REGISTER_EVENT
2.3 ESP_MQT_CLIENT_START_START
2.4 esp_mqtt_client_unsubscribe
3. MQTT 客户端 3.1 主流程
3.2 配置 MQTT 参数
首先定义 MQTT 客户端配置结构。 最低配置是输入 MQTT 服务器所需的信息。 请使用网址。 esp_mqtt_client_config_t mqtt_cfg = { .uri = CONFIG_BROKER_URL,}; esp_mqtt_client_config_t 结构为:
typedef struct { mqtt_event_callback_t event_handle; /*Callback*/ const char *host; /*!< MQTT 服务器域名(ipv4 为字符串)*/ const char *uri /*!< MQTT 服务器域名 */ uint32_t port; /*!< MQTT 服务器端口*/ const char *client_id; /*MQTT 客户端默认名称为 ESP32_ 在 MAC 后加 3hex*/ const char *用户名; /*MQTT密码*/ const char *lwt_topic; /*!< LWT 主题,默认为空 */ const char *lwt_msg; /*!< LWT 信息,默认为空 */ int lwt_qos /*!< LWT 消息质量*/ int lwt_retain; *!< LWT 消息保留标志*/ int lwt_msg_len; /*!< LWT 消息长度*/ int disable_clean_session; /*!< mqtt clean session,默认为 true*/ int keepalive; /*MQTT 心跳,默认为 120 秒* / bool disable_auto_reconnect; /*错误,断开后重连,true则未连接*/ void *user_context; /*用户信息*/ int task_prio; /*!< MQTT任务优先级,默认5,可以用make menuconfig更改 */ int task_stack; /*!< MQTT 任务堆栈大小,默认 6144 字节,可以通过 make menuconfig 更改 */ intbuffer_size ; /*!< MQTT 收发器缓存,默认为 1024 */ const char *cert_pem /* 指向 PEM 格式的指针用于服务器验证的证书数据(使用SSL),默认值为空,需要验证服务器没有*/ const char *client_cert_pem; /*指向用于 SSL 相互身份验证的 PEM 格式证书数据的指针。 默认值为空。 如果不需要相互身份验证,则不需要。 如果不为空,您还必须指定客户端密钥。 */ const char *client_key_pem; /*指向用于 SSL 相互认证的 PEM 格式的私钥数据的指针。 如果不需要相互身份验证,则默认值为空且不需要。 如果不为空,则还必须指定“client-cert-pem”。 */ esp_mqtt_transport_t Transport; /*覆盖 URI Transport*/} esp_mqtt_client_config_t; 3.3 初始化 MQTT 客户端
接下来,通过 esp_mqtt_client_init() 获取 MQTT 客户端结构体指针。 该参数是MQTT客户端配置结构。
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); 3.4 注册 MQTT 事件
默认情况下,MQTT 客户端使用事件循环库来发出相关的 MQTT 事件(例如连接、订阅、发布等)。
因此,您需要注册一个MQTT事件并填充MQTT事件处理函数mqtt_event_handler()。
static void mqtt_event_handler(void *handler_args, esp_event_base_t Base, int32_tevent_id, void *event_data) { ESP_LOGD( TAG, "从事件循环调度的事件,base=%s, event_id=%d", base, event_id) ;dler_cb(event_data);} 第一个参数为MQTT客户端结构体,第二个参数为事件ID对应的事件类型,第三个参数为事件处理函数,第四个参数为事件处理函数参数。 3.5 启动 MQTT 客户端 esp_mqtt_client_start(client); 3.6 MQTT 事件处理 static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_tevent){ esp_mqtt_client_handle_t client =event->client; // your_context_ t *context = event [k 4]> 上下文; event->event_id) { case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0); msg_id=%d", msg_id); msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); ESP_LOGI(TAG, "订阅成功。msg_id=%d", msg_id); msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); ESP_LOGI(TAG, "发送订阅成功。msg_id=%d", msg_id); msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); "注销成功。msg_id=%d", msg_id); case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event- > msg_id); msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); ESP_LOGI(TAG, "发布成功。msg_id=%d ", msg_id); (TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);泄漏; 案例 MQTT_EVENT_PUBLISHED: ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); 销毁; 案例 MQTT_EVENT_DATA: ESP_LOGI(TAG, "MQTT_EVENT_DATA"); r/n", 事件->topic_len, 事件->topic); printf("DATA=%.*s/r/n", 事件->data_len, 事件->data ); destroy; for MQTT_EVENT_ERROR: ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); destroy; 默认: ESP_LOGI(TAG, "Other event ID:%d",event->event_id); } return ESP_OK;根据
examples/protocols/mqtt/tcp 中的例程的示例代码。 Server address.host = "192.168.61.67",
/* 根据 MQTT (over TCP) 示例进行更改。 此示例代码属于公共领域(如果您愿意,也可以获得 CC0 许可)。根据适用法律的要求或书面同意,本软件按“原样”分发,不附有任何明示或暗示的保证或条件。 */#include #include #include #include #include "esp_wifi.h"#include "esp_system.h"#include "nvs_flash.h"#include "esp_event.h"#include "esp_netif.h"#include "protocol_examples_common.h" h"#include "freertos/FreeRTOS.h"#include "freertos /task.h"#include "freertos/semphr.h"#include "freertos/queue.h"#include "lwip/sockets.h"#include " lwip/dns.h"#include "lwip/netdb.h" #include "esp_log.h"#include "mqtt_client.h"static const char *TAG = "MQTT_EXAMPLE";static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_tevent){ // MQTT 客户端获取结构体指针 esp_mqtt_client_handle_t client =event->client; // your_cont;ext_t *context = event->context; // 通过事件ID处理每个对应的事件 switch (event->event_id) { case MQTT_EVENT_CONNECTED: // MQTT 连接事件 ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");客户端公开主题功能。 主题为 /topic/qos1,服务质量为 qos1,公共数据为 data-3 msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0 );发布成功。msg_id=%d", msg_id); // MQTT 客户端订阅主题函数。 主题为/topic/qos0,服务质量为qos0。 msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0" , 0); ESP_LOGI(TAG, "发送订阅成功。msg_id=%d", msg_id); // MQTT 客户端订阅主题函数 . 主题为/topic/qos1,服务质量为qos1。 msg_id = esp_mqtt_client_subscribe(client, "/topic/ qos1", 1); ESP_LOGI(TAG, "订阅成功提交ssful, msg_id=%d", msg_id); // 取消订阅 MQTT 客户端主题函数 msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); ESP_LOGI(TAG, "发送取消订阅成功, msg_id=%d" , msg_id) ; Break; case MQTT_EVENT_DISCONNECTED: // MQTT 断开事件 ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED") Break; case MQTT_EVENT_SUBSCRIBED: // MQTT 订阅成功事件 ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d",event[ k4 ]>msg_id) ) ; msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); ESP_LOGI(TAG, "发送成功, msg_id=%d", msg_id); case MQTT_EVENT_UNSUBSCRIBED : // MQTT 取消订阅事件ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d",event->msg_id);destroy; case MQTT_EVENT_PUBLISHED: // MQTT 发布成功事件 ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d",event->msg_id); destroy; // MQTT 接收数据事件 ESP_LOGI(TAG, " MQTT_EVENT_DATA" ); printf("TOPIC=%.*s/r/n", event->topic_len, event->topic); printf("DATA=%.*s /r/n", event ->data_len, event->data); 对于 MQTT_EVENT_ERROR: ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); 默认值: ESP_LOGI(TAG, "其他事件 ID: %d",event-> event_id); destroy; } return ESP_OK;}static void mqtt_event_handler(void *handler_args, esp_event_base_t Base, int32_tevent_id, void *event_data) { ESP_LOGD(TAG, "从事件循环调度的事件base=%s,event_id=%d",base,event_id); mqtt_event_handler_cb(event_data);}static void mqtt_app_start(void){ // 1. 定义 MQTT 客户端配置结构并输入 MQTT URL esp_mqtt_client_config_t mqtt_cfg = { .host = "192.168.61.67", // MQTT 服务器地址 .port = 1883, // MQTT 服务器端口}; #if CONFIG_BROKER_URL_FROM_STDIN char line[128] if (strcmp(mqtt_cfg.uri, "FROM_STDIN") == 0 ) { int count = 0; printf("请输入 mqtt 代理 URL/n"); (count 0 && c)
评论前必须登录!
注册