ESP32学习笔记(46)——MQTT客户端
一、MQTT簡(jiǎn)介
1.1 實(shí)現(xiàn)方式
實(shí)現(xiàn)MQTT協(xié)議需要客戶(hù)端和服務(wù)器端通訊完成,在通訊過(guò)程中,MQTT協(xié)議中有三種身份:發(fā)布者(Publish)、代理(Broker)(服務(wù)器)、訂閱者(Subscribe)。其中,消息的發(fā)布者和訂閱者都是客戶(hù)端,消息代理是服務(wù)器,消息發(fā)布者可以同時(shí)是訂閱者。
MQTT傳輸?shù)南⒎譃?#xff1a;主題(Topic)和負(fù)載(payload)兩部分:
Topic,可以理解為消息的類(lèi)型,訂閱者訂閱(Subscribe)后,就會(huì)收到該主題的消息內(nèi)容(payload);
payload,可以理解為消息的內(nèi)容,是指訂閱者具體要使用的內(nèi)容。
- MQTT服務(wù)器的主要工作是數(shù)據(jù)分發(fā),沒(méi)有數(shù)據(jù)保存功能。
- 可以訂閱自己發(fā)布的主題,服務(wù)器就是回發(fā)測(cè)試。
- MQTT讓邏輯變得更清晰,需要什么訂閱什么。
- 走標(biāo)準(zhǔn)化流程,解放了私有協(xié)議制定、實(shí)現(xiàn)、調(diào)試、測(cè)試一整套復(fù)雜的流程。
1.2 ESP-MQTT
ESP-MQTT 是 MQTT 協(xié)議客戶(hù)端的實(shí)現(xiàn)(MQTT 是輕量級(jí)的發(fā)布/訂閱消息協(xié)議)。
- 支持 MQTT over TCP、SSL with mbedtls、MQTT over Websocket、MQTT over Websocket Secure。
- 使用 URI 輕松設(shè)置
- 多個(gè)實(shí)例(一個(gè)應(yīng)用程序中有多個(gè)客戶(hù)端)
- 支持訂閱、發(fā)布、身份驗(yàn)證、最后遺囑消息、保持活動(dòng) ping 和所有 3 個(gè) QoS 級(jí)別(它應(yīng)該是一個(gè)功能齊全的客戶(hù)端)。
ESP-IDF 編程指南——ESP-MQTT
二、API說(shuō)明
以下 MQTT 客戶(hù)端接口位于 components/mqtt/esp-mqtt/include/mqtt_client.h 。
2.1 esp_mqtt_client_init
2.2 esp_mqtt_client_register_event
2.3 esp_mqtt_client_start
2.4 esp_mqtt_client_publish
2.5 esp_mqtt_client_subscribe
2.6 esp_mqtt_client_unsubscribe
三、MQTT客戶(hù)端
3.1 主要流程
3.2 配置MQTT參數(shù)
首先,要定義一個(gè) MQTT 客戶(hù)端配置結(jié)構(gòu)體,最小配置即填入 MQTT 服務(wù)器的 URL 即可。
esp_mqtt_client_config_t mqtt_cfg = {.uri = CONFIG_BROKER_URL, };esp_mqtt_client_config_t 結(jié)構(gòu)體如下:
typedef struct {mqtt_event_callback_t event_handle; /*回調(diào)*/const char *host; /*!< MQTT 服務(wù)器域名(ipv4 as string)*/const char *uri; /*!< MQTT 服務(wù)器域名 */uint32_t port; /*!< MQTT服務(wù)器端口*/const char *client_id; /*MQTT Client的名字默認(rèn)是ESP32_加上MAC后3hex*/const char *username; /*MQTT用戶(hù)名*/const char *password; /*MQTT密碼*/const char *lwt_topic; /*!< LWT主題,默認(rèn)為空*/const char *lwt_msg; /*!< LWT信息,默認(rèn)為空*/int lwt_qos; /*!< LWT消息質(zhì)量*/int lwt_retain; /*!< LWT保留消息標(biāo)志*/int lwt_msg_len; /*!< LWT消息長(zhǎng)度*/int disable_clean_session; /*!< mqtt clean session,默認(rèn)為真*/int keepalive; /*MQTT心跳,默認(rèn)120秒 */bool disable_auto_reconnect; /*錯(cuò)誤,斷開(kāi)后重連,true不連*/void *user_context; /*用戶(hù)信息 */int task_prio; /*!< MQTT任務(wù)優(yōu)先級(jí),默認(rèn)為5,可以在make menuconfig中修改*/int task_stack; /*!< MQTT 任務(wù)堆棧大小,默認(rèn)6144 bytes,可以在make menuconfig中修改*/int buffer_size; /*!< MQTT收發(fā)緩存,默認(rèn)1024 */const char *cert_pem; /*指向用于服務(wù)器驗(yàn)證(使用SSL)的PEM格式的證書(shū)數(shù)據(jù)的指針,默認(rèn)值為空,不需要驗(yàn)證服務(wù)器 */const char *client_cert_pem; /*指向用于SSL相互身份驗(yàn)證的PEM格式的證書(shū)數(shù)據(jù)的指針,默認(rèn)值為空,如果不需要相互身份驗(yàn)證,則不需要。如果不為空,還必須提供“客戶(hù)機(jī)密鑰”。*/const char *client_key_pem; /*指向用于SSL相互身份驗(yàn)證的PEM格式的私鑰數(shù)據(jù)的指針,默認(rèn)值為空,如果不需要相互身份驗(yàn)證,則不需要。如果不為空,還必須提供“client-cert-pem”。*/esp_mqtt_transport_t transport; /*覆蓋URI傳輸*/ } esp_mqtt_client_config_t;3.3 初始化MQTT客戶(hù)端
然后通過(guò) esp_mqtt_client_init() 獲取一個(gè) MQTT 客戶(hù)端結(jié)構(gòu)體指針,參數(shù)是 MQTT 客戶(hù)端配置結(jié)構(gòu)體。
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);3.4 注冊(cè)MQTT事件
默認(rèn)情況下,MQTT 客戶(hù)端使用事件循環(huán)庫(kù)來(lái)發(fā)布相關(guān)的 MQTT 事件(已連接,已訂閱,已發(fā)布等)。
所以我們要注冊(cè)一個(gè) MQTT 事件,填入 MQTT 事件處理函數(shù) mqtt_event_handler(),
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);mqtt_event_handler_cb(event_data); }- 第一個(gè)參數(shù)為MQTT客戶(hù)端結(jié)構(gòu)體,
- 第二個(gè)是事件ID對(duì)應(yīng)的事件類(lèi)型,
- 第三個(gè)參數(shù)即事件處理函數(shù),
- 第四個(gè)參數(shù)為事件處理函數(shù)的參數(shù)。
3.5 開(kāi)啟MQTT客戶(hù)端
esp_mqtt_client_start(client);3.6 MQTT事件處理
static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) {esp_mqtt_client_handle_t client = event->client;int msg_id;// your_context_t *context = event->context;switch (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);ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);break;case MQTT_EVENT_DISCONNECTED:ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");break;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, "sent publish successful, msg_id=%d", msg_id);break;case MQTT_EVENT_UNSUBSCRIBED:ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);break;case MQTT_EVENT_PUBLISHED:ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);break;case MQTT_EVENT_DATA: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);break;case MQTT_EVENT_ERROR:ESP_LOGI(TAG, "MQTT_EVENT_ERROR");break;default:ESP_LOGI(TAG, "Other event id:%d", event->event_id);break;}return ESP_OK; }四、示例代碼
根據(jù) examples\protocols\mqtt\tcp 中的例程修改
根據(jù)服務(wù)器地址修改.host = "192.168.61.67",
五、搭建本地MQTT服務(wù)器
EMQ官網(wǎng)下載:https://www.emqx.com/zh/downloads?product=broker
- 下載EMQ X開(kāi)源版
- 解壓后進(jìn)入 emqx-windows-4.3.8\emqx\bin 目錄
- Shift+右鍵在此處打開(kāi) Powershell 窗口,輸入命令 emqx start
- 打開(kāi)瀏覽器,輸入 http://127.0.0.1:18083/,賬號(hào) admin,密碼 public,進(jìn)入管理界面
- 工具 - Websocket,選擇連接
- 訂閱主題和發(fā)布消息
六、運(yùn)行測(cè)試
配置連接方式:
選擇WIFI連接方式,并修改要連接路由器的SSID和密碼
調(diào)試打印:
服務(wù)器查看:
? 由 Leung 寫(xiě)于 2021 年 9 月 8 日
? 參考:第二十一章 ESP32開(kāi)發(fā)MQTT Client ESP-IDF
ESP32學(xué)習(xí)筆記(6)MQTT應(yīng)用
ESP32開(kāi)發(fā)之路(9)—ESP32連接到MQTT服務(wù)器
總結(jié)
以上是生活随笔為你收集整理的ESP32学习笔记(46)——MQTT客户端的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 编程中的幂等性(一):http幂等性
- 下一篇: C++奥赛第四弹——阿克曼函数