【ESP32】打造全网最强esp-idf基础教程——18.ESP32连接MQTT Broker

news2024/11/15 11:03:22

ESP32连接MQTT Broker

一、MQTT Broker
       在开始ESP32编程之前,我们要先来看看公共主流的MQTT服务器可供使用,所谓的公共MQTT服务器就是一些网站给我们提供了在线的MQTT Broker,我可以直接利用其进行 MQTT 学习、测试甚至是小规模使用,而无需再自行部署,方便快捷,节省时间与精力成本,这对于我们用ESP32来做一些MQTT调试再适合不过了,由于这些MQTT服务器很多都是外国的,它们的可访问性、延时等都有着一些问题。这里我推荐一个目前为止我一直在用的。
mqtt://broker-cn.emqx.io
为了方便测试,我们可以在电脑上下载一个MQTTX客户端软件,后续的话可以看到与ESP32是如何进行数据交互的,下载地址在https://mqttx.app/zh。下载安装过程就不介绍了,打开软件之后设置如下,其余按照默认值即可

       修改完后点击右上角Connect,连接成功后,新建一个订阅,订阅主题是/test/topic1,消息等级QoS=1,点击Confirm。这样我们在电脑上的客户端就部署完毕了。 

二、ESP32上的MQTT程序
       完整代码在esp32-board/mqtt中。
       mqtt连接之前,需要WiFi连接成功,因此需要WIFI——STA章节的代码,我在WIFI——STA章节代码上做了一些改善,增加了一个回调函数通知主函数WiFi已连接。
/** 事件回调函数 

/** 事件回调函数
 * @param arg   用户传递的参数
 * @param event_base    事件类别
 * @param event_id      事件ID
 * @param event_data    事件携带的数据
 * @return 无
*/
static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{   
    if(event_base == WIFI_EVENT)
    {
        switch (event_id)
        {
        case WIFI_EVENT_STA_START:      //WIFI以STA模式启动后触发此事件
            esp_wifi_connect();         //启动WIFI连接
            break;
        case WIFI_EVENT_STA_CONNECTED:  //WIFI连上路由器后,触发此事件
            ESP_LOGI(TAG, "connected to AP");
            break;
        case WIFI_EVENT_STA_DISCONNECTED:   //WIFI从路由器断开连接后触发此事件
            esp_wifi_connect();             //继续重连
            ESP_LOGI(TAG,"connect to the AP fail,retry now");
            break;
        default:
            break;
        }
    }
    if(event_base == IP_EVENT)                  //IP相关事件
    {
        switch(event_id)
        {
            case IP_EVENT_STA_GOT_IP:           //只有获取到路由器分配的IP,才认为是连上了路由器
                if(wifi_cb)
                    wifi_cb(WIFI_CONNECTED);
                ESP_LOGI(TAG,"get ip address");
                break;
        }
    }
}
请看IP_EVENT_STA_GOT_IP事件处理,会执行wifi_cb函数通知WIFI_CONNECTED事件。	接下来请看main.c文件实现
#define MQTT_ADDRESS    "mqtt://broker-cn.emqx.io"     //MQTT连接地址
#define MQTT_PORT       1883                        //MQTT连接端口号
#define MQTT_CLIENT     "mqttx_d11213"              //Client ID(设备唯一,大家最好自行改一下)
#define MQTT_USERNAME   "hello"                     //MQTT用户名
#define MQTT_PASSWORD   "12345678"                  //MQTT密码

#define MQTT_PUBLIC_TOPIC      "/test/topic1"       //测试用的,推送消息主题
#define MQTT_SUBSCRIBE_TOPIC    "/test/topic2"      //测试用的,需要订阅的主题
//定义一个事件组,用于通知main函数WIFI连接成功
#define WIFI_CONNECT_BIT     BIT0
static EventGroupHandle_t   s_wifi_ev = NULL;
//MQTT客户端操作句柄
static esp_mqtt_client_handle_t     s_mqtt_client = NULL;
//MQTT连接标志
static bool   s_is_mqtt_connected = false;
/**
 * mqtt连接事件处理函数
 * @param event 事件参数
 * @return 无
 */
static void aliot_mqtt_event_handler(void* event_handler_arg,
                                        esp_event_base_t event_base,
                                        int32_t event_id,
                                        void* event_data)
{
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;
    // your_context_t *context = event->context;
    switch ((esp_mqtt_event_id_t)event_id) {
        case MQTT_EVENT_CONNECTED:  //连接成功
            ESP_LOGI(TAG, "mqtt connected");
            s_is_mqtt_connected = true;
            //连接成功后,订阅测试主题
            esp_mqtt_client_subscribe_single(s_mqtt_client,MQTT_SUBSCRIBE_TOPIC,1);
            break;
        case MQTT_EVENT_DISCONNECTED:   //连接断开
            ESP_LOGI(TAG, "mqtt disconnected");
            s_is_mqtt_connected = false;
            break;
        case MQTT_EVENT_SUBSCRIBED:     //收到订阅消息ACK
            ESP_LOGI(TAG, " mqtt subscribed ack, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_UNSUBSCRIBED:   //收到解订阅消息ACK
            break;
        case MQTT_EVENT_PUBLISHED:      //收到发布消息ACK
            ESP_LOGI(TAG, "mqtt publish ack, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_DATA:
            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);       //收到Pub消息直接打印出来
            printf("DATA=%.*s\r\n", event->data_len, event->data);
            break;
        case MQTT_EVENT_ERROR:
            ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
            break;
        default:
            break;
    }
}
/** 启动mqtt连接
 * @param 无
 * @return 无
*/
void mqtt_start(void)
{
    esp_mqtt_client_config_t mqtt_cfg = {0};
    mqtt_cfg.broker.address.uri = MQTT_ADDRESS;
    mqtt_cfg.broker.address.port = MQTT_PORT;
    //Client ID
    mqtt_cfg.credentials.client_id = MQTT_CLIENT;
    //用户名
    mqtt_cfg.credentials.username = MQTT_USERNAME;
    //密码
    mqtt_cfg.credentials.authentication.password = MQTT_PASSWORD;
    ESP_LOGI(TAG,"mqtt connect->clientId:%s,username:%s,password:%s",mqtt_cfg.credentials.client_id,
    mqtt_cfg.credentials.username,mqtt_cfg.credentials.authentication.password);
    //设置mqtt配置,返回mqtt操作句柄
    s_mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
    //注册mqtt事件回调函数
    esp_mqtt_client_register_event(s_mqtt_client, ESP_EVENT_ANY_ID, aliot_mqtt_event_handler, s_mqtt_client);
    //启动mqtt连接
    esp_mqtt_client_start(s_mqtt_client);
}
/** wifi事件通知
 * @param 无
 * @return 无
*/
void wifi_event_handler(WIFI_EV_e ev)
{
    if(ev == WIFI_CONNECTED)
    {
        xEventGroupSetBits(s_wifi_ev,WIFI_CONNECT_BIT);
    }
}
void app_main(void)
{
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        //NVS出现错误,执行擦除
        ESP_ERROR_CHECK(nvs_flash_erase());
        //重新尝试初始化
        ESP_ERROR_CHECK(nvs_flash_init());
    }
    s_wifi_ev = xEventGroupCreate();
    EventBits_t ev = 0;
    //初始化WIFI,传入回调函数,用于通知连接成功事件
    wifi_sta_init(wifi_event_handler);
    //一直监听WIFI连接事件,直到WiFi连接成功后,才启动MQTT连接
    ev = xEventGroupWaitBits(s_wifi_ev,WIFI_CONNECT_BIT,pdTRUE,pdFALSE,portMAX_DELAY);
    if(ev & WIFI_CONNECT_BIT)
    {
        mqtt_start();
    }
    static char mqtt_pub_buff[64];
    while(1)
    {
        int count = 0;
        //延时2秒发布一条消息到/test/topic1主题
        if(s_is_mqtt_connected)
        {
            snprintf(mqtt_pub_buff,64,"{\"count\":\"%d\"}",count);
            esp_mqtt_client_publish(s_mqtt_client, MQTT_PUBLIC_TOPIC,
                            mqtt_pub_buff, strlen(mqtt_pub_buff),1, 0);
            count++;
        }
        vTaskDelay(pdMS_TO_TICKS(2000));
    }
    return;
}

最后附上相关资料:

ESP32教程资料链接:
https://pan.baidu.com/s/1kCjD8yktZECSGmHomx_veg?pwd=q8er 
提取码:q8er 

配套源码下载地址:
esp32-board: esp32开发板配套的经典例程

鉴于实验需要开发板的支持,我也设计了一款ESP32开发板,包含部分传感器模块,1.69寸LCD高亮屏,Type-C一键下载,方便大家学习和做各种实验。开发板链接如下:

https://item.taobao.com/item.htm?ft=t&id=802401650392&spm=a21dvs.23580594.0.0.4fee645eXpkfcp&skuId=5635015963649
 

​​

请大家多多支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1933873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

表格竖向展示

最近在做手机端web页面,页面中需要有个表格来显示数据,但是由于数据太多页面太窄,table展示横向滑动的话感觉很丑。所以让表格竖向显示了 具体页面如下: 实现代码:当然代码里面绑定的数据啊什么的你都可以修改为自己的内容&#…

【软件建模与设计】-05-软件建模和设计方法概览

目录 1、COMET基于用例的软件生命周期 1.1、需求建模 1.2、分析建模 1.3、设计建模 1.4、增量软件构建 1.5、增量软件集成 1.6、系统测试 2、COMET与其他软件过程比较 2.1、与RUP对比 2.2、与螺旋模型对比 3、需求、分析和设计建模 3.1、需求建模活动 3.2、分析建…

机器学习入门【经典的CIFAR10分类】

模型 神经网络采用下图 我使用之后发现迭代多了之后一直最高是正确率65%左右,然后我自己添加了一些Relu激活函数和正则化,现在正确率可以有80%左右。 模型代码 import torch from torch import nnclass YmModel(nn.Module):def __init__(self):super(…

【香橙派】Orange pi AIpro开发板评测,与树莓派的横向对比以及实机性能测试

一、前言 在人工智能领域飞速发展的时代,国产厂商们也是紧随时代的步伐,迅龙公司联合华为推出了一款全新的开发板 Orange pi AIpro 作为一款建设人工智能新生态的开发板,它可广泛适用于AI边缘计算、深度视觉学习及视频流AI分析、视频图像分析…

ssh远程登录另一台linux电脑

大部分的博客内容所说的安装好ssh服务后,terminal输入 ssh -p port_number clientnameserver_ip 之后输入密码等等就可以登上别人的电脑 但是这是有一个前提的,就是这两台电脑要在同一个局域网下面。 如果很远呢? 远到不在同一个网下面怎么办…

【智能算法应用】粒子群算法求解带出入点车间布局设计问题

目录 1.算法原理2.数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】粒子群算法(PSO)原理及实现 设施布局问题(Facility Layout Problem, FLP),主要目的是在给定的区域内有效地放置不同设备或部件&am…

大模型学习笔记十一:视觉大模型

一、判别式模型和生成式模型 1)判别式模型Discriminative ①给某一个样本,判断属于某个类别的概率,擅长分类任务,计算量少。(学习策略函数Y f(X)或者条件概率P(YIX)) ②不能反映训练数据本身的特性 ③学习…

JavaScript学习笔记(九)

56、JavaScript 类 56.1 JavaScript 类的语法 请使用关键字 class 创建一个类。 请始终添加一个名为 constructor() 的方法。 JavaScript 类不是对象。 它是 JavaScript 对象的模板。 语法: class ClassName {constructor() { ... } }示例:例子创…

【无人值守】对数据中心电力分配系统发展的影响

数据中心在现代信息发展中承载着巨量数据的计算、存储、挖掘、分析和应用等多个方面的功能,是国计民生各行业的多样化的信息化的资产。对稳定的运行与安全运维是基本需求也是重要的保障。 数据中心属于高能耗产业,对用电负荷大且要求极度稳定。除了对电力…

一文-深入了解Ansible常见模块、安装和部署

1 Ansible 介绍 Ansible是一个配置管理系统configuration management system, python 语言是运维人员必须会的语言, ansible 是一个基于python 开发的(集合了众多运维工具 puppet、cfengine、chef、func、fabric的优点)自动化运维工具, 其功能实现基于ss…

HarmonyOS介绍

一、什么是HarmonyOS HarmonyOS是新一代的智能终端操作系统,为不同设备的智能化、互联与协同提供了统一的语言,为用户带来简捷、流畅、连续、安全可靠的全场景交互体验。 二、HarmonyOS的核心理念 1、一次开发 多端部署 指的是一个工程&#xf…

题解|2023暑期杭电多校05

【原文链接】 (补发)题解|2023暑期杭电多校05 1001.Typhoon 计算几何 题目大意 依次给定 n n n 个坐标 P P P ,预测的台风路线为按顺序两两连接给定坐标所得的折线 现在有 m m m 个庇护所的坐标 S S S ,求每个庇护所到台风…

基于AT89C51单片机的多功能自行车测速计程器(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机的多功能自行车测速计程器的详情介绍,如果对您有帮助的话,还请关注一下哦,如果有资源方面的需要可以联系我。 目录 选题背景 原理图 PCB图 仿真图 代码 系统论文 资源下载 选题背景 美丽的夜晚&…

c++树(一)定义,遍历

目录 树的定义 树的基本术语 树的初始起点:我们定义为根 树的层次: 树的定义: 树的性质 性质1: 性质2: 树形结构存储的两种思路 树的遍历模板 树上信息统计方式1-自顶向下统计 树上信息统计方式2-自底向上统…

【漏洞复现】泛微E-Cology WorkflowServiceXml SQL注入漏洞

0x01 产品简介 泛微e-cology是一款由泛微网络科技开发的协同管理平台,支持人力资源、财务、行政等多功能管理和移动办公。 0x02 漏洞概述 泛微OAE-Cology 接口/services/WorkflowServiceXml 存在SQL注入漏洞,可获取数据库权限,导致数据泄露…

Purple Pi OH在Android11下测试WiFi和LAN的TCP和UDP传输速率

本文适用于在Purple Pi OH在Andriod11下如何测试WiFi和LAN的TCP和UDP传输速率。触觉智能的Purple Pi OH鸿蒙开源主板,是华为Laval官方社区主荐的一款鸿蒙开发主板。 该主板主要针对学生党,极客,工程师,极大降低了开源鸿蒙开发者的…

C语言 ——— 在控制台上打印动态变化的菱形

目录 代码要求 代码实现 代码要求 输入 整数line &#xff0c;菱形的上半部分的长度就为line&#xff08;动态变化的菱形&#xff09; 菱形由 "*" 号构成 代码实现 #include<stdio.h> int main() {// 上半长int line 0;scanf("%d", &line)…

mysql常用函数五大类

mysql常用函数 1. 第一类&#xff1a;数值函数1.1 圆周率pi的值1.2 求绝对值1.3 返回数字的符号1.4 开平方&#xff0c;根号1.5 求两个数的余数1.6 截取正数部分1.7 向上取整数1.8 向下取整数1.9 四舍五入函数1.10 随机数函数1.11 数值左边补位函数1.12 数值右边补位函数1.13 次…

【网络工具】Charles 介绍及环境配置

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/iAmAo &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会整理一些工作或学习中用到的工具介绍给大家~ &#x1f4d8;Charles 系列其它文章&#xff1a;【网络…

PySide在Qt Designer中使用QTableView 显示表格数据

在 PySide6 中&#xff0c;可以使用 Qt Model View 架构中的 QTableView 部件来显示和编辑表格数据。 1、创建ui文件 在Qt Designer中新建QMainWindow&#xff0c;命名为csvShow.ui。QMainWindow上有两个部件&#xff1a;tableview和btn_exit。 2、使用pyuic工具将ui文件转换为…