日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

ESP32学习笔记(46)——MQTT客户端

發布時間:2023/12/14 c/c++ 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ESP32学习笔记(46)——MQTT客户端 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、MQTT簡介

1.1 實現方式

實現MQTT協議需要客戶端和服務器端通訊完成,在通訊過程中,MQTT協議中有三種身份:發布者(Publish)、代理(Broker)(服務器)、訂閱者(Subscribe)。其中,消息的發布者和訂閱者都是客戶端,消息代理是服務器,消息發布者可以同時是訂閱者。

MQTT傳輸的消息分為:主題(Topic)和負載(payload)兩部分:

Topic,可以理解為消息的類型,訂閱者訂閱(Subscribe)后,就會收到該主題的消息內容(payload);

payload,可以理解為消息的內容,是指訂閱者具體要使用的內容。

  • MQTT服務器的主要工作是數據分發,沒有數據保存功能。
  • 可以訂閱自己發布的主題,服務器就是回發測試。
  • MQTT讓邏輯變得更清晰,需要什么訂閱什么。
  • 走標準化流程,解放了私有協議制定、實現、調試、測試一整套復雜的流程。

1.2 ESP-MQTT

ESP-MQTT 是 MQTT 協議客戶端的實現(MQTT 是輕量級的發布/訂閱消息協議)。

  • 支持 MQTT over TCP、SSL with mbedtls、MQTT over Websocket、MQTT over Websocket Secure。
  • 使用 URI 輕松設置
  • 多個實例(一個應用程序中有多個客戶端)
  • 支持訂閱、發布、身份驗證、最后遺囑消息、保持活動 ping 和所有 3 個 QoS 級別(它應該是一個功能齊全的客戶端)。

ESP-IDF 編程指南——ESP-MQTT

二、API說明

以下 MQTT 客戶端接口位于 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客戶端

3.1 主要流程

3.2 配置MQTT參數

首先,要定義一個 MQTT 客戶端配置結構體,最小配置即填入 MQTT 服務器的 URL 即可。

esp_mqtt_client_config_t mqtt_cfg = {.uri = CONFIG_BROKER_URL, };

esp_mqtt_client_config_t 結構體如下:

typedef struct {mqtt_event_callback_t event_handle; /*回調*/const char *host; /*!< MQTT 服務器域名(ipv4 as string)*/const char *uri; /*!< MQTT 服務器域名 */uint32_t port; /*!< MQTT服務器端口*/const char *client_id; /*MQTT Client的名字默認是ESP32_加上MAC后3hex*/const char *username; /*MQTT用戶名*/const char *password; /*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,默認為真*/int keepalive; /*MQTT心跳,默認120秒 */bool disable_auto_reconnect; /*錯誤,斷開后重連,true不連*/void *user_context; /*用戶信息 */int task_prio; /*!< MQTT任務優先級,默認為5,可以在make menuconfig中修改*/int task_stack; /*!< MQTT 任務堆棧大小,默認6144 bytes,可以在make menuconfig中修改*/int buffer_size; /*!< MQTT收發緩存,默認1024 */const char *cert_pem; /*指向用于服務器驗證(使用SSL)的PEM格式的證書數據的指針,默認值為空,不需要驗證服務器 */const char *client_cert_pem; /*指向用于SSL相互身份驗證的PEM格式的證書數據的指針,默認值為空,如果不需要相互身份驗證,則不需要。如果不為空,還必須提供“客戶機密鑰”。*/const char *client_key_pem; /*指向用于SSL相互身份驗證的PEM格式的私鑰數據的指針,默認值為空,如果不需要相互身份驗證,則不需要。如果不為空,還必須提供“client-cert-pem”。*/esp_mqtt_transport_t transport; /*覆蓋URI傳輸*/ } 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_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); }
  • 第一個參數為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_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; }

四、示例代碼

根據 examples\protocols\mqtt\tcp 中的例程修改
根據服務器地址修改.host = "192.168.61.67",

/* MQTT (over TCP) ExampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied. */#include <stdio.h> #include <stdint.h> #include <stddef.h> #include <string.h> #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"#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_t event) {// 獲取MQTT客戶端結構體指針esp_mqtt_client_handle_t client = event->client;int msg_id;// your_context_t *context = event->context;// 通過事件ID來分別處理對應的事件switch (event->event_id) {case MQTT_EVENT_CONNECTED: // MQTT連上事件ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");// MQTT Client發布主題函數,主題是/topic/qos1,服務質量qos1,發布的數據是data-3msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);// MQTT Client訂閱主題函數,主題是/topic/qos0,服務質量qos0msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);// MQTT Client訂閱主題函數,主題是/topic/qos1,服務質量qos1msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);// MQTT Client取消訂閱主題函數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: // MQTT斷開連接事件ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");break;case MQTT_EVENT_SUBSCRIBED: // MQTT發送訂閱成功事件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: // MQTT取消訂閱事件ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);break;case MQTT_EVENT_PUBLISHED: // MQTT發布成功事件ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);break;case MQTT_EVENT_DATA: // 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);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; }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); }static void mqtt_app_start(void) {// 1、定義一個MQTT客戶端配置結構體,輸入MQTT的urlesp_mqtt_client_config_t mqtt_cfg = {.host = "192.168.61.67", // MQTT服務器地址.port = 1883, // MQTT服務器端口}; #if CONFIG_BROKER_URL_FROM_STDINchar line[128];if (strcmp(mqtt_cfg.uri, "FROM_STDIN") == 0) {int count = 0;printf("Please enter url of mqtt broker\n");while (count < 128) {int c = fgetc(stdin);if (c == '\n') {line[count] = '\0';break;} else if (c > 0 && c < 127) {line[count] = c;++count;}vTaskDelay(10 / portTICK_PERIOD_MS);}mqtt_cfg.uri = line;printf("Broker url: %s\n", line);} else {ESP_LOGE(TAG, "Configuration mismatch: wrong broker url");abort();} #endif /* CONFIG_BROKER_URL_FROM_STDIN */// 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) {ESP_LOGI(TAG, "[APP] Startup..");ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());esp_log_level_set("*", ESP_LOG_INFO);esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);ESP_ERROR_CHECK(nvs_flash_init());ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.* Read "Establishing Wi-Fi or Ethernet Connection" section in* examples/protocols/README.md for more information about this function.*/ESP_ERROR_CHECK(example_connect());mqtt_app_start(); }

五、搭建本地MQTT服務器

EMQ官網下載:https://www.emqx.com/zh/downloads?product=broker

  • 下載EMQ X開源版
  • 解壓后進入 emqx-windows-4.3.8\emqx\bin 目錄
  • Shift+右鍵在此處打開 Powershell 窗口,輸入命令 emqx start
  • 打開瀏覽器,輸入 http://127.0.0.1:18083/,賬號 admin,密碼 public,進入管理界面
  • 工具 - Websocket,選擇連接
  • 訂閱主題和發布消息

六、運行測試

配置連接方式:

選擇WIFI連接方式,并修改要連接路由器的SSID和密碼

調試打印:

服務器查看:


? 由 Leung 寫于 2021 年 9 月 8 日

? 參考:第二十一章 ESP32開發MQTT Client ESP-IDF
    ESP32學習筆記(6)MQTT應用
    ESP32開發之路(9)—ESP32連接到MQTT服務器

總結

以上是生活随笔為你收集整理的ESP32学习笔记(46)——MQTT客户端的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。