摘要:一簡介實現方式實現協議需要客戶端和服務器端通訊完成,在通訊過程中,協議中有三種身份發布者代理服務器訂閱者。其中,消息的發布者和訂閱者都是客戶端,消息代理是服務器,消息發布者可以同時是訂閱者。
實現MQTT協議需要客戶端和服務器端通訊完成,在通訊過程中,MQTT協議中有三種身份:發布者(Publish)、代理(Broker)(服務器)、訂閱者(Subscribe)。其中,消息的發布者和訂閱者都是客戶端,消息代理是服務器,消息發布者可以同時是訂閱者。
MQTT傳輸的消息分為:主題(Topic)和負載(payload)兩部分:
Topic,可以理解為消息的類型,訂閱者訂閱(Subscribe)后,就會收到該主題的消息內容(payload);
payload,可以理解為消息的內容,是指訂閱者具體要使用的內容。
ESP-MQTT 是 MQTT 協議客戶端的實現(MQTT 是輕量級的發布/訂閱消息協議)。
以下 MQTT 客戶端接口位于 components/mqtt/esp-mqtt/include/mqtt_client.h 。
首先,要定義一個 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;
然后通過 esp_mqtt_client_init()
獲取一個 MQTT 客戶端結構體指針,參數是 MQTT 客戶端配置結構體。
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
默認情況下,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);}
esp_mqtt_client_start(client);
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) Example This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*/#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"#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-3 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); // MQTT Client訂閱主題函數,主題是/topic/qos0,服務質量qos0 msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); // MQTT Client訂閱主題函數,主題是/topic/qos1,服務質量qos1 msg_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的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("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();}
EMQ官網下載:https://www.emqx.com/zh/downloads?product=broker
emqx-windows-4.3.8/emqx/bin
目錄emqx start
http://127.0.0.1:18083/
,賬號 admin
,密碼 public
,進入管理界面配置連接方式:
選擇WIFI連接方式,并修改要連接路由器的SSID和密碼
調試打印:
服務器查看:
? 由 Leung 寫于 2021 年 9 月 8 日
? 參考:第二十一章 ESP32開發MQTT Client ESP-IDF
ESP32學習筆記(6)MQTT應用
ESP32開發之路(9)—ESP32連接到MQTT服務器
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/119623.html
摘要:教程傳送門基于平臺開發連接巴法云簡介實驗準備硬件軟件實驗步驟點燈實驗發送溫濕度指令升級總結關于巴法云專注于開源,智造,創新,分享。 Arduino教程傳送門????...
摘要:超簡單深度睡眠模式下遠程采集溫濕度信息項目背景相關技術深度睡眠模式溫濕度采集數據收發前后端實現后端前端項目背景自己用收納箱做了一個用于存放打印耗材的干燥箱,想用閑置的開發板和溫濕度傳感器做一個遠程溫濕度監測的小項目。 ...
摘要:具體操作如下創建自己的設備進入到阿里云控制臺,找到物聯網平臺,創建屬于自己的設備點擊公共實例進行創建里面有個設備管理,點擊產品,里面有個創建產品輸入名稱即可,然后選擇標準品類這里我創建的是溫濕度檢測。 ...
摘要:前言芯片接口占用管腳數量比以太網的少,版線布局可更精簡。網卡芯片介紹接口網卡芯片是為方物聯網行業進以太網通信而開發出的解決方案。此應用可用于監控家庭物聯網網關搭建等。 前言 ????DM9051NP芯片?SPI接口占用管腳數量比以太網PHY的RMII/MII少,PCBA版線布局可更精簡。...
閱讀 2457·2021-11-23 09:51
閱讀 1872·2021-10-13 09:40
閱讀 1384·2021-09-30 10:01
閱讀 594·2021-09-26 09:46
閱讀 2250·2021-09-23 11:55
閱讀 1395·2021-09-10 10:51
閱讀 2261·2021-09-09 09:33
閱讀 2234·2019-08-29 17:25