摘要:一简介实现方式实现协议需要客户端和服务器端通讯完成,在通讯过程中,协议中有三种身份发布者代理服务器订阅者。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
实现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服务器
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/119623.html
摘要:教程传送门基于平台开发连接巴法云简介实验准备硬件软件实验步骤点灯实验发送温湿度指令升级总结关于巴法云专注于开源,智造,创新,分享。 Arduino教程传送门????...
摘要:超简单深度睡眠模式下远程采集温湿度信息项目背景相关技术深度睡眠模式温湿度采集数据收发前后端实现后端前端项目背景自己用收纳箱做了一个用于存放打印耗材的干燥箱,想用闲置的开发板和温湿度传感器做一个远程温湿度监测的小项目。 ...
摘要:具体操作如下创建自己的设备进入到阿里云控制台,找到物联网平台,创建属于自己的设备点击公共实例进行创建里面有个设备管理,点击产品,里面有个创建产品输入名称即可,然后选择标准品类这里我创建的是温湿度检测。 ...
摘要:前言芯片接口占用管脚数量比以太网的少,版线布局可更精简。网卡芯片介绍接口网卡芯片是为方物联网行业进以太网通信而开发出的解决方案。此应用可用于监控家庭物联网网关搭建等。 前言 DM9051NP芯片 SPI接口占用管脚数量比以太网PHY的RMII/MII少,PCBA版线布局可更精简。...
阅读 2439·2021-11-23 09:51
阅读 1866·2021-10-13 09:40
阅读 1372·2021-09-30 10:01
阅读 588·2021-09-26 09:46
阅读 2232·2021-09-23 11:55
阅读 1385·2021-09-10 10:51
阅读 2240·2021-09-09 09:33
阅读 2225·2019-08-29 17:25