Arduino MQTT客户端库PubSubClient快速入门
文章目录
- 目的
- 基础说明
- 示例代码
- 总结
目的
MQTT是比较常用在物联网设备中的通讯协议,这篇文章将使用 Arudino ESP32
作为MQTT客户端进行通讯使用演示。目前Arduino的MQTT客户端库中最常使用的是 PubSubClient
,所以本文也将以此进行说明。
主页:https://pubsubclient.knolleary.net/
项目地址:https://github.com/knolleary/pubsubclient
目前 PubSubClient
库版本为 v2.8
,主要基于 MQTT 3.1.1
,不支持 MQTT 5.0
的新增特性,订阅主题只支持 Qos 0 和 1
。
This library provides a client for doing simple publish/subscribe messaging with a server that supports MQTT.
基础说明
MQTT的一些基础内容可以参考下面文章:
《MQTT基础入门与资料收集》
因为测试需要有 MQTT Broker(服务器)
,可以参考上面文章进行启动,或者也可以申请一个免费的在线的云服务使用。
PubSubClient
库使用很简单,主要就是分为下面几步:
- 声明
PubSubClient
对象; - 因为MQTT需要在TCP之上工作,所以需要给
PubSubClient
对象一个TCP对象; - 使用
setServer
方法设置MQTT服务器的地址和端口号; - 使用
setCallback
方法设置通讯消息回调函数void callback(char *topic, byte *payload, unsigned int length)
(如果不需要订阅消息则无需此步骤); - 使用
connect
方法启动连接; - 使用
subscribe
方法订阅主题或使用publish
方法向某个主题发布消息;
上面步骤中 2、3、4 步顺序并无要求,并且可以在第一步声明对象的构造函数中直接传入。
在使用 connect
方法进行连接时可以选择填入 Will Qos
Will Retain
Will Message
cleanSession
信息(默认为 0 0 0 1
)。发送消息时可以选择填入 retained
(默认为 false
)。
默认情况下发送和接收数据都会依赖buffer,当发送或者接收的消息比buffer可容纳的空间(默认256字节)大的时候将会忽略这条消息。可以使用 setBufferSize
方法来设置buffer大小。
上面的 publish
方法发送消息时会先将消息拷贝到缓存,这在大数据发送时效率并不好,可以先使用 beginPublish
方法启动传输,然后单次或多次使用 write
方法写数据(也可以使用 print
等方法),最后使用 endPublish
完成本次消息发送,减少一次拷贝,效率上会高很多。
可以使用 setKeepAlive
方法来设置 Keep Alive
时间(默认为15s)。
使用 disconnect
方法可以关闭连接,使用 connected
方法可以检查是否连接。使用 unsubscribe
方法可以取消订阅消息。
使用 state
方法可以获得 PubSubClient
对象当前的状态,状态定义如下:
// Possible values for client.state()
#define MQTT_CONNECTION_TIMEOUT -4
#define MQTT_CONNECTION_LOST -3
#define MQTT_CONNECT_FAILED -2
#define MQTT_DISCONNECTED -1
#define MQTT_CONNECTED 0
#define MQTT_CONNECT_BAD_PROTOCOL 1
#define MQTT_CONNECT_BAD_CLIENT_ID 2
#define MQTT_CONNECT_UNAVAILABLE 3
#define MQTT_CONNECT_BAD_CREDENTIALS 4
#define MQTT_CONNECT_UNAUTHORIZED 5
示例代码
#include <WiFi.h>
#include <PubSubClient.h>// WiFi相关配置信息
const char *wifi_ssid = "********";
const char *wifi_password = "********";// MQTT相关配置信息
const char *mqtt_broker_addr = "********"; // 服务器地址
const uint16_t mqtt_broker_port = 1883; // 服务端口号
const char *mqtt_username = "********"; // 账号(非必须)
const char *mqtt_password = "********"; // 密码(非必须)
const uint16_t mqtt_client_buff_size = 4096; // 客户端缓存大小(非必须)
String mqtt_client_id = "esp32_client"; // 客户端ID
const char *mqtt_topic_pub = "esp32/test"; // 需要发布到的主题
const char *mqtt_topic_sub = "esp32/test"; // 需要订阅的主题WiFiClient tcpClient;
PubSubClient mqttClient;// MQTT消息回调函数,该函数会在PubSubClient对象的loop方法中被调用
void mqtt_callback(char *topic, byte *payload, unsigned int length)
{Serial.printf("Message arrived in topic %s, length %d\n", topic, length);Serial.print("Message:");for (int i = 0; i < length; i++){Serial.print((char)payload[i]);}Serial.println("\n----------------END----------------");
}void setup()
{Serial.begin(115200);Serial.println();// 连接网络Serial.printf("\nConnecting to %s", wifi_ssid);WiFi.begin(wifi_ssid, wifi_password);while (WiFi.status() != WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("ok.");Serial.print("IP address: ");Serial.println(WiFi.localIP());// 设置MQTT客户端mqttClient.setClient(tcpClient);mqttClient.setServer(mqtt_broker_addr, mqtt_broker_port);mqttClient.setBufferSize(mqtt_client_buff_size);mqttClient.setCallback(mqtt_callback);
}unsigned long previousConnectMillis = 0; // 毫秒时间记录
const long intervalConnectMillis = 5000; // 时间间隔
unsigned long previousPublishMillis = 0; // 毫秒时间记录
const long intervalPublishMillis = 5000; // 时间间隔void loop()
{unsigned long currentMillis = millis(); // 读取当前时间// 连接MQTT服务器if (!mqttClient.connected()) // 如果未连接{if (currentMillis - previousConnectMillis > intervalConnectMillis){previousConnectMillis = currentMillis;mqtt_client_id += String(WiFi.macAddress()); // 每个客户端需要有唯一的ID,不然上线时会把其他相同ID的客户端踢下线if (mqttClient.connect(mqtt_client_id.c_str())) // 尝试连接服务器// if (mqttClient.connect(mqtt_client_id.c_str(), mqtt_username, mqtt_password)){mqttClient.publish(mqtt_topic_pub, "hello mqtt!"); // 连接成功后可以发送消息mqttClient.subscribe(mqtt_topic_sub); // 连接成功后可以订阅主题}}}// 定期发送消息if (mqttClient.connected()){if (currentMillis - previousPublishMillis >= intervalPublishMillis) // 如果和前次时间大于等于时间间隔{previousPublishMillis = currentMillis;mqttClient.publish(mqtt_topic_pub, "naisu 233~~~");}}// 处理MQTT事务mqttClient.loop();
}
上面代码示例演示的是非加密的mqtt,实际业务中更多的可能会使用加密的mqtts,这个时候TCP客户端就需要使用 #include <WiFiClientSecure.h>
库中的 WiFiClientSecure
对象了。TCP客户端需要使用 setCACert
或者 getFingerprintSHA256
等方法设置证书或者指纹,另外可能需要从NTP服务器获取时间。( WiFiClientSecure对象可以使用 setInsecure
方法,可以不用管证书这些,测试使用没问题,实际使用中可能会有安全风险)
总结
MQTT作为客户端使用本身比较简单,PubSubClient用起来也非常简单,基本上一般的使用有上面内容就够了。
相关文章:
Arduino MQTT客户端库PubSubClient快速入门
文章目录 目的基础说明示例代码总结 目的 MQTT是比较常用在物联网设备中的通讯协议,这篇文章将使用 Arudino ESP32 作为MQTT客户端进行通讯使用演示。目前Arduino的MQTT客户端库中最常使用的是 PubSubClient ,所以本文也将以此进行说明。 主页…...

视频集中存储/云存储/磁盘阵列EasyCVR平台接入RTSP设备出现离线情况的排查
安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…...

部署Springboot项目注意事项
步骤 步骤 1:将数据库内容在云服务器上的数据库部署一份 我使用mariadb;会出现一些不兼容现象;我们需要把默认值删掉 2:配置文件你得修改地方 a:linux是磁盘区分(像我自己项目用来储存验证码的文件我们得换这个配置;…...
深度解析:DDoS攻击与先进防御策略
目录 DDoS 介绍 DDoS 攻击理论 DDoS 介绍 DDoS(分布式拒绝服务)攻击是一种恶意网络活动,旨在通过同时向目标系统发送大量请求或流量,使其无法正常运行或提供服务。攻击者通常利用网络上的多个计算机和设备,形成一个&…...
NLP | 论文摘要文本分类
基于论文摘要的文本分类与关键词抽取挑战赛2023 iFLYTEK A.I.开发者大赛-讯飞开放平台 环境需求:Anaconda-JupyterNotebook,或者百度AIStudio 赛题解析: 【文本二分类任务】根据论文摘要等信息理解,将论文划分为0-1两…...

Linux / Ubuntu磁盘扩容
测试时遇到了shell脚本执行错误的问题,找到脚本编写的楼哥,才发现自己给虚拟机的磁盘已经满了,没想到啊,业务的解压操作,这么费磁盘,那就需要进行磁盘的扩展,记录一下 1、首先停掉虚拟机&#…...

【ChatGPT 指令大全】怎么使用ChatGPT来辅助知识学习
目录 概念解说 简易教学 深度教学 教学与测验 解释一个主题的背后原理 总结 在当今信息时代,互联网的快速发展为我们获取知识提供了前所未有的便利。而其中,人工智能技术的应用也为我们的学习和交流带来了新的可能性。作为一种基于自然语言处理的人…...

URL编码指南
URL简介 URL 是统一资源定位符(Uniform Resource Locator)的缩写。它是用于在互联网上定位并访问资源的一种标识方式。 URL通常由以下几个组成部分组成: 协议(Protocol):指示要使用的协议,如…...
Java mail邮件开发 OA办公系统
目录 1 Java mail邮件开发 OA办公系统 1.1 ExitServlet 1.1.1 //退出系统 1.2 LoginAction 1.2.1 //登录Action Java mail邮件开发 OA办公系统 ExitServlet package com.email.ser...

ElasticSearch的客户端操作
ElasticSearch的客户端操作 1、客户端介绍 官方文档地址: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html 实际开发中,有多种方式操作Elasticsearch: 客户端工具:发送http请求(RESTful风格)操作…...

如何快速的合并多个PPT使之成为一个PPT?
如何快速的合并多个PPT使之成为一个PPT? 项目过程中,经常给客户汇报,经常做PPT,有时候,需要把之前的ppt内容整合到新的内容中,如何快速合并以及使用呢? 幻灯片(PPT中)点…...
【微信小程序】列表滚动触底更新实现
微信小程序开发系列 目录 前言一、上拉触底事件函数onReachBottom二、实现 前言 在微信小程序开发中经常遇到分页列表需要滚动到底部之后进行请求数据更新,下面介绍如何进行触底更新分页展示。使用到页面上拉触底事件的处理函数onReachBottom。 一、上拉触底事件函…...
2023全国大学生数学建模竞赛A题B题C题D题E题思路+模型+代码+论文
目录 一. 2023国赛数学建模思路: 赛题发布后会第一时间发布选题建议,思路,模型代码等 详细思路获取见文末名片,9.7号第一时间更新 二.国赛常用的模型算法: 三、算法简介 四.超重要!!&…...

Git常见操作
一、全局配置命令 配置级别: –local(默认,高级优先):只影响本地仓库 –global(中优先级):只影响所有当前用户的git仓库 –system(低优先级):影响到全系统的git仓库 1…...

thinkphp6前后端验证码分离以及验证
1.验证码接口生成验证码: public function verify(){return captcha(); } 也可以自己写方法 2.验证方法和普通模式session验证有区别,需要改原文件: 修改后的代码: <?php // +---------------------------------------------------------------------- // | ThinkP…...
jenkinsfile自动部署接口
复制创建新流水线 从预先创建的job中获取 config.xml 或根据需要创建另一个 curl -X GET http://xxx.xxx.xxxx.com/job/backup-data/config.xml -u test:xxxxxxxxxxxxxxxxxx-o config.xml 生成Crumb CRUMB$(curl -s http://xxxxxxx.xxx.xxx.com/crumbIssuer/api/xml?xpathc…...
26. 删除有序数组中的重复项
26. 删除有序数组中的重复项 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的…...
vue父页面获取子组件绑定值
<el-form-item label"图文详情" prop"imageText"><div><el-button type"primary" link>组件</el-button><WangEditor v-model"ruleForm.imageText"></WangEditor></div> </el-form-item…...

FPGA_学习_17_IP核_ROM(无延迟-立即输出)
由于项目中关于厂商提供的温度-偏压曲线数据已经被同事放在ROM表了,我这边可用直接调用。 今天在仿真的时候,发现他的ROM表用的IP核是及时输出的,就是你地址给进去,对应地址的ROM数据就立马输出,没有延迟。 我打开他的…...

CentOS7.6安装mysql8.0.34
一、查看服务器相关信息 cat /etc/redhat-release cat /proc/version [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) [rootlocalhost ~]# cat /proc/version Linux version 3.10.0-957.el7.x86_64 (mockbuildkbuilder.bsys.centos.org) …...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...