ESP系列入门教程(四)——之MQTT通信实现设备反控【分别附上 ESP32 + ESP8266 的具体代码】

ESP系列入门教程<四>

    • 概要
    • 技术名词简介
      • ● ESP系列简介
      • ● MQTT简介
    • 硬件连接实现(同教程2,没有变化)
    • 代码实现
      • ●Demo:通过MQTT进行开关灯反控
        • ○ ESP8266代码
        • ○ ESP32代码
    • 特别鸣谢

概要

最近在跟着几个大佬的教学视频做项目。陆续会更新记录一些要点,便于后期总结笔记的时候进行引用。
也可以帮助有心跟着一起复刻的宝子们,更好地捋清思路。

【本系列教程 - 总目标】:
使用ESP系列板卡,通过MQTT进行数据通信,达到远程控制多个传感器的效果。

ESP芯片官方技术文档链接
https://www.espressif.com.cn/zh-hans/support/documents/technical-documents

◆配置说明
硬件板卡:ESP系列板卡 <本系列教程以ESP32ESP8266为例>

硬件元件:

  • DHT11温湿度传感器
  • 一颗LED灯
  • 一个5v驱动的继电器
  • 一个按键开关
  • 杜邦线若干

◆需求概述

【本篇章目标】
ESP系列入门教程(一) 中,我们已经完成了ESP系列驱动继电器,通过按键达到控制LED亮灭的效果

ESP系列入门教程(二)中,我们完成了DHT11温湿度传感器驱动控制

ESP系列入门教程(三)中,我们完成了MQTT通信的实现按键开关灯数据的上报

本章,我们将基于之前的代码,继续进行开发通过MQTT通信进行远程反控,通过指令达到远程反控ESP板卡上的LED灯亮灭的效果,宝子们最好实操一下哦,期待大家的结果反馈~

同时附上代码(ESP32和ESP8266代码),希望对宝子们有所帮助。

技术名词简介

● ESP系列简介

ESP芯片是一种由乐鑫科技(Espressif Systems)开发的低功耗无线通信芯片。

ESP芯片系列包括ESP8266和ESP32两个主要型号。这些芯片具有强大的处理能力和丰富的外设接口,适用于物联网(IoT)应用和嵌入式系统开发。

◆ESP8266
是一款高度集成的Wi-Fi芯片,具有低功耗和低成本的特点。它支持TCP/IP协议栈,可以通过Wi-Fi连接到互联网,并与其他设备进行通信。ESP8266可以作为主控芯片,与传感器、执行器等设备进行通信,实现智能家居、智能农业、智能工业等应用。

◆ESP32
是ESP8266的升级版本,除了具备Wi-Fi功能外,还增加了蓝牙(Bluetooth)功能。ESP32具有更高的处理能力和更多的外设接口,支持更复杂的应用场景。它可以作为Wi-Fi和蓝牙网关,连接多个设备并实现数据传输和控制。

ESP芯片具有开放的开发环境和丰富的开发资源,开发者可以使用Arduino IDE、MicroPython等开发工具进行编程。此外,乐鑫科技还提供了丰富的文档和示例代码,方便开发者快速上手和开发应用。

● MQTT简介

MQTT是一种轻量级的消息传输协议,用于在低带宽和不稳定的网络环境中传输小型数据包。
设计宗旨和目标:简单、轻量级和易于实现
因此使其成为物联网应用中常用的通信协议之一

MQTT协议基于发布/订阅模式,这使得消息的传输变得高效和灵活,可以实现一对多的通信。
通信实现的过程中有两个主要角色:发布者和订阅者。

  • 发布者(pub):负责将消息发布到特定的主题(Topic)。
  • 订阅者(sub):用来订阅感兴趣的主题,以接收相关的消息。

MQTT协议具有以下特点:

轻量级:MQTT协议的设计非常简单,消息头部信息很小,使得它在网络带宽有限的情况下能够高效传输。
可靠性:MQTT协议支持三种消息传输质量等级:至多一次(At most once)、至少一次(At least once)和刚好一次(Exactly once),可以根据应用需求选择适当的等级。
异步通信:MQTT协议支持异步通信,发布者和订阅者之间的通信不需要实时连接,可以通过消息队列进行中转。
低功耗:MQTT协议适用于低功耗设备,可以在资源受限的设备上运行,如传感器、嵌入式设备等。

硬件连接实现(同教程2,没有变化)

ESP8266和ESP32引脚图有很多部分不一样,详情请参考前面写好的:ESP系列入门教程(一)
https://blog.csdn.net/qq_38141255/article/details/135597139?spm=1001.2014.3001.5501
里面有详细的引脚图,有需要请对照配置。

以ESP32图示为例:
图来自B站大佬:莽小石
在这里插入图片描述

代码实现

代码前说明,对于MQTT通信功能,ESP32和ESP8266,在实际操作的过程中,开始逐步出现了略微的不同。
具体缘由,期望大佬可以留言给大家讲讲。(*╹▽╹*)大佬我们做朋友好不好

我先直接分享一下我实际调试过程中的代码。
ESP32和ESP8266是分开的,宝子们在调测的时候,注意对照入座。

●Demo:通过MQTT进行开关灯反控

PS:由于两块板子是分开调测的,所以在代码实现上可能会有略微的不同,但逻辑是一样的。

实验描述
代码刷入后,ESP板卡上电后,自动连接wifi,若wifi连接成功后。MQTT将会自动连接和订阅MQTT_Topic(可自定义,但要和MQTT服务器订阅发布的topic一致)。

  • MQTT数据上报:通过按键开关灯时,MQTT服务器将会受到ESP板卡发布的开关灯状态数据。
  • MQTT设备反控:在MQTT服务器上,或者第三端测试环境中,通过发布MQTT_Topic,会发现ESP板卡根据接收到的开关灯控制指令,进行LED开关控制。
    开关控制指令为:1或0。代码定义的宏变量为:UE_LED_On / UE_LED_Off

PS:WiFi连接信息 和 MQTT连接信息 需要重新填写,根据自己测试环境填写真实数据。

○ ESP8266代码
#include <Arduino.h>
#include <WiFiClient.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>// WiFi连接信息
#define WIFI_SSID "AA"
#define WIFI_PASS "12345678"
// MQTT服务器信息
#define MQTT_HOST "你的MQTT服务器IP"
#define MQTT_PORT 1883
#define MQTT_CLIENT_ID "My_Device"
#define MQTT_USER "你的MQTT服务器用户名"
#define MQTT_PASS "你的MQTT服务器密码"#define MQTT_Topic "test_ESP8266" 
#define LED_On     "LED_On"
#define LED_Off    "LED_Off"#define UE_MQTT_Topic "UE_Control" 
#define UE_LED_On     "1"
#define UE_LED_Off    "0"// 创建WiFi客户端和MQTT客户端实例
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
Ticker ticker;// 定义按键和继电器的引脚
const int buttonPin = 2;   // 按键连接到引脚2
const int relayPin  = 4;    // 继电器连接到引脚4int buttonState = 0;       // 保存当前按键状态(低电平或高电平)
int lastButtonState = 0;   // 保存上一次的按键状态
unsigned long lastDebounceTime  = 0;     // 上次去抖动的时间
unsigned long debounceDelay     = 120;   // 去抖动延迟时间,单位:毫秒// 处理按键状态
void handleButton() {int reading = digitalRead(buttonPin);if (reading != lastButtonState) {lastDebounceTime = millis();}if ((millis() - lastDebounceTime) > debounceDelay) {if (reading != buttonState) {buttonState = reading;if (buttonState == HIGH) {toggleRelay();}}}lastButtonState = reading;
}
// 切换继电器状态
void toggleRelay() {if (digitalRead(relayPin) == HIGH) {turnRelayOff();} else {turnRelayOn();}
}// 打开继电器
void turnRelayOn() {digitalWrite(relayPin, HIGH);Serial.println("Relay ON");mqttClient.publish(MQTT_Topic, LED_On);
}// 关闭继电器
void turnRelayOff() {digitalWrite(relayPin, LOW);Serial.println("Relay OFF");mqttClient.publish(MQTT_Topic, LED_Off);
}void connectWIFI() {// 连接WIFI热点WiFi.begin(WIFI_SSID, WIFI_PASS);int retryCount = 1;while (WiFi.status() != WL_CONNECTED) {Serial.println("正在连接WiFi...");delay(3000);}Serial.println("WIFI连接成功");Serial.println("IP地址: " + WiFi.localIP().toString());
}// 设置MQTT连接函数
void setupMQTT() {// 配置MQTT服务器mqttClient.setServer(MQTT_HOST, MQTT_PORT);// 设置回调函数mqttClient.setCallback(recvMsg);
}void sendMsg(int status) {if (mqttClient.connected()) {String topic = MQTT_Topic;String payload = "";if(status==1){payload = LED_On;}else{payload = LED_Off;}if (mqttClient.publish(topic.c_str(), payload.c_str())) {// if (mqttClient.publish(topic.c_str(), payload.c_str())) {Serial.println("MQTT消息发送成功");} else {Serial.println("MQTT消息发送失败");}} else {Serial.println("MQTT服务器未连接");}
}void recvMsg(char *topic, uint8_t *payload, size_t length) {Serial.println("topic: " + String(topic));Serial.println("payload: " + String((char *)payload).substring(0, length) + "length: " + String(length));// 将payload转换为字符串String message = "";for (int i = 0; i < length; i++) {message += (char)payload[i];}Serial.println(message);// 根据消息内容执行相应的操作if (strcmp(topic, UE_MQTT_Topic) == 0) {if (message == UE_LED_On) {turnRelayOn();} else if (message == UE_LED_Off) {turnRelayOff();}}
}void connectMQTT() {if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS)) {Serial.println("MQTT服务器连接成功");String topic = UE_MQTT_Topic;if (mqttClient.subscribe(topic.c_str())) {Serial.println("MQTT主题订阅成功");} else {Serial.println("MQTT主题订阅失败");}// ticker.attach(3, sendMsg);} else {Serial.println("MQTT服务器连接失败");Serial.print(mqttClient.state());ticker.detach();delay(3000);}
}// 初始化函数
void setup() {// put your setup code here, to run once:// 设置波特率Serial.begin(115200);//设置灯引脚pinMode(buttonPin, INPUT);pinMode(relayPin , OUTPUT);// 连接WIFI热点connectWIFI();// 配置MQTT服务器setupMQTT();// 连接MQTT服务器connectMQTT();
} void loop() {// put your main code here, to run repeatedly:// 检查MQTT连接是否成功,如果未连接则尝试重新连接if (mqttClient.connected()) {mqttClient.loop();} else {connectMQTT();}// 读取按键状态并执行相应操作handleButton();
}
○ ESP32代码
#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>// WiFi连接信息
const char* ssid = "AA";
const char* password = "12345678";// MQTT服务器信息
const char* mqttServer = "你的MQTT服务器IP";
const int mqttPort = 1883;
const char* mqttUsername = "你的MQTT服务器用户名";
const char* mqttPassword = "你的MQTT服务器密码";// 创建WiFi客户端和MQTT客户端实例
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);// 定义按键和继电器的引脚
const int buttonPin = 2;   // 按键连接到引脚2
const int relayPin = 4;    // 继电器连接到引脚4int buttonState = 0;       // 保存当前按键状态(低电平或高电平)
int lastButtonState = 0;   // 保存上一次的按键状态
unsigned long lastDebounceTime = 0;  // 上次去抖动的时间
unsigned long debounceDelay = 120;    // 去抖动延迟时间,单位:毫秒// 设置MQTT连接函数
void setupMQTT() {mqttClient.setServer(mqttServer, mqttPort);mqttClient.setCallback(callback); // 设置回调函数
}// 重新连接MQTT服务器函数
void reconnectMQTT() {while (!mqttClient.connected()) {Serial.println("正在连接到MQTT...");if (mqttClient.connect("ESP32Client", mqttUsername, mqttPassword)) {Serial.println("连接到MQTT");mqttClient.subscribe("ESP"); // 订阅"ESP"主题} else {Serial.print("MQTT连接失败,rc=");Serial.print(mqttClient.state());Serial.println(" 5秒钟后重试...");delay(5000);}}
}// 设置WiFi连接函数
void setupWiFi() {WiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("正在连接WiFi...");}Serial.println("已连接到WiFi");
}// MQTT消息回调函数
void callback(char* topic, byte* payload, unsigned int length) {Serial.print("收到来自主题 '");Serial.print(topic);Serial.print("' 的消息: ");// 将payload转换为字符串String message = "";for (int i = 0; i < length; i++) {message += (char)payload[i];}Serial.println(message);// 根据消息内容执行相应的操作if (strcmp(topic, "ESP") == 0) {if (message == "1") {turnRelayOn();} else if (message == "0") {turnRelayOff();}}
}// 初始化函数
void setup() {Serial.begin(115200);pinMode(buttonPin, INPUT);pinMode(relayPin, OUTPUT);setupWiFi();setupMQTT();
}// 主循环函数
void loop() {// 检查MQTT连接状态,如果未连接则尝试重新连接if (!mqttClient.connected()) {reconnectMQTT();}// 处理MQTT消息mqttClient.loop();// 读取按键状态并执行相应操作handleButton();
}// 处理按键状态
void handleButton() {int reading = digitalRead(buttonPin);if (reading != lastButtonState) {lastDebounceTime = millis();}if ((millis() - lastDebounceTime) > debounceDelay) {if (reading != buttonState) {buttonState = reading;if (buttonState == HIGH) {toggleRelay();}}}lastButtonState = reading;
}// 切换继电器状态
void toggleRelay() {if (digitalRead(relayPin) == HIGH) {turnRelayOff();} else {turnRelayOn();}
}// 打开继电器
void turnRelayOn() {digitalWrite(relayPin, HIGH);Serial.println("Relay ON");mqttClient.publish("kaiguan", "kai");
}// 关闭继电器
void turnRelayOff() {digitalWrite(relayPin, LOW);Serial.println("Relay OFF");mqttClient.publish("kaiguan", "guan");
}

特别鸣谢

B站大佬:莽小石

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

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

相关文章

02--数据定义语言DDL

1、数据定义语言DDL 1.1 操作数据库-DDL 创建数据库 create database 数据库名称; 创建数据库&#xff0c;并指定字符集 create database 数据库名称 character set 字符集名; 查询所有数据库的名称 show databases; 查询某个数据库的字符集:查询某个数据库的创建语句及字…

微服务介绍

背景 微服务是什么?杜克大学教授DanAriely说过一段非常出名的话&#xff0c;用来表述Big Data的发展现状。我觉得把这句话放到微服务身上也极其贴切。 Micro-services is like teenage sex: Everyone talks about it, nobody really knows how to do it, everyo ne thinks ev…

excel(vab)删除空行

删除第一、二、三列位空的所有行&#xff08;8000)行范围以内 代码如下&#xff1a; Sub Macro1()Dim hang As Integer For hang 8000 To 1 Step -1If Sheet1.Cells(hang, 1) "" And Sheet1.Cells(hang, 2) "" And Sheet1.Cells(hang, 3) "&quo…

系统性学习vue-vue中的ajax

vue中的ajax 配置代理常用发送Ajax请求方式跨域方式一方式二 vue-resource插槽默认插槽具名插槽作用域插槽 配置代理 常用发送Ajax请求方式 xhr new XMLHttpRequest() 在真正开发中不常用&#xff0c;比较麻烦jQuery 封装了xhraxios 封装了xhr 与jQuery相比优势是&#xff1a…

怎样才能找到合适的产品说明书模板 方法献上

制作一份专业而吸引人的产品手册对于企业来说至关重要。然而&#xff0c;对于许多企业和个人而言&#xff0c;制作产品手册可能是一个挑战&#xff0c;因为需要一定的设计和排版能力。为了帮助大家更轻松地制作出优质的产品手册&#xff0c;下面将向大家推荐三款优秀的产品手册…

Ovtio不同版本下载

关注 M r . m a t e r i a l , \color{Violet} \rm Mr.material\ , Mr.material , 更 \color{red}{更} 更 多 \color{blue}{多} 多 精 \color{orange}{精} 精 彩 \color{green}{彩} 彩&#xff01; 主要专栏内容包括&#xff1a; †《LAMMPS小技巧》&#xff1a; ‾ \textbf…

2024年汉字小达人区级选拔备考——附加题:汉字和国学常识

上海的孩子们已经率先开启了悠长的寒假生活。在寒假期间&#xff0c;除了完成寒假生活、学校安排和要求外&#xff0c;还可以做些什么呢&#xff1f;不妨来为2024年汉字小达人做些准备吧&#xff01;每天花个15分钟左右&#xff0c;背一背、做一做&#xff0c;轻松掌握汉字小达…

翻译: Streamlit从入门到精通 构建一个机器学习应用程序 三

Streamlit从入门到精通 系列&#xff1a; 翻译: Streamlit从入门到精通 基础控件 一翻译: Streamlit从入门到精通 显示图表Graphs 地图Map 主题Themes 二 1. 构建一个机器学习应用程序 在这一部分&#xff0c;我将带你了解我做的一个关于贷款预测的项目。 贷款的主要利润直…

“15个必备的自动化测试工具,助你构建2024年的自动化策略!“

以下为作者观点&#xff1a; 如何选择正确的自动化测试工具&#xff1f;自动化测试工具是旨在通过自动化测试脚本验证功能或非功能软件需求的应用程序&#xff0c;帮助加快发布速度、提高项目质量并强化成果。 自动化测试工具可以帮助开发测试人员轻松创建、运行和维护测试&a…

PlatformIO中ESP8266使用GxEPD库和U8G2库驱动 2.9寸黑白墨水屏显示中文

Content 0. 前言1. 安装platformIO环境2. 新建工程3. 添加外部库4. 修改U8g2_for_Adafruit_GFX库5. 代码和烧录 0. 前言 墨水屏是黄鱼淘的&#xff0c;效果还不错。 U8G2库一直编译不进去&#xff0c;显示汉字始终不太美观&#xff0c;个人一直不太喜欢汉字取模的方法&#x…

【RabbitMQ】RabbitMQ高级:死信队列和延迟队列

目录 设置TTL&#xff08;过期时间&#xff09;概述RabbitMQ使用TTL原生API案例springboot案例 死信队列概述原生API案例springboot案例 延迟队列概述插件实现延迟队列安装插件代码 TTL实现延迟队列实现延迟队列优化 设置TTL&#xff08;过期时间&#xff09; 概述 在电商平台…

Komodor:Kubernetes 监控工具全面指南

为了方便起见&#xff0c;Komodor 提供了一个简单的 Web 界面&#xff0c;以帮助您监控 Kubernetes 集群的状态。它拥有付费和免费增值计划&#xff0c;除了在出现问题时通知用户外&#xff0c;还拥有一系列方便的工具&#xff0c;用于跟踪和管理集群中部署的资源的状态。让我们…

计算机网络 应用层

文章目录 应用层域名系统 DNS域名系统概述互联网的域名结构域名服务器 文件传送协议FTP 概述FTP 的基本工作原理简单文件传送协议 TFTP 远程终端协议 TELNET万维网 WWW统一资源定位符 URL超文本传送协议 HTTP万维网的信息检索系统 电子邮件电子邮件概述简单邮件传送协议 SMTP邮…

2024年机器人和人工智能将通过4种方式改变行业

文 | BFT机器人 前言&#xff1a; 2023年是人工智能界充满创造性和突破性的一年&#xff0c;包括生成式人工智能在内的人工智能 (AI) 技术的出现引起了全球的关注并占据了头条新闻。然而&#xff0c;生成式人工智能在企业中的应用仍处于早期阶段&#xff0c;如何最好地利用这项…

大物②练习题解

1.【单选题】关于磁场中磁通量&#xff0c;下面说法正确的是&#xff08; D&#xff09; A、穿过闭合曲面的总磁通量不一定为零 B、磁感线从闭合曲面内穿出&#xff0c;磁通量为负 C、磁感线从闭合曲面内穿入&#xff0c;磁通量为正D、穿过闭合曲面的总磁通量一定为零 磁感线从…

“轻松粘贴,高效办公:自动粘贴文本技术让您事半功倍

"在快节奏的现代工作中&#xff0c;时间就是金钱。使用自动粘贴文本技术&#xff0c;让您告别繁琐的手动操作&#xff0c;提高工作效率。一键粘贴&#xff0c;释放您的双手&#xff0c;让您专注于创作和思考。让工作更高效&#xff0c;生活更精彩&#xff01;" 首先…

广告投放场景中ABtest分析的评价、优化和决策建议

目录 写在开头1. AB测试基础知识1.1 AB测试概述1.2 原理和流程1.3 广告领域中的AB测试应用 2. 评价广告投放中的AB测试2.1 关键指标选择与解释2.2 统计学方法应用 3. AB测试分析中的常见问题与解决方案3.1 样本偏差3.2 季节性影响3.3 测试时长选择3.4 结果误解与分析失误 4. 优…

《TrollStore巨魔商店》TrollStore2安装使用教程支持IOS14.0-16.6.1

TrollStore(巨魔商店) 简单的说就相当于一个永久的免费证书&#xff0c;它可以给你的iPhone和iPad安装任何你想要安装的App软件&#xff0c;而且不需要越狱,不用担心证书签名过期的问题&#xff0c;不需要个人签名和企业签名。 支持的版本&#xff1a; TrollStore安装和使用教…

Markdown 流程图绘制详解

✍️作者简介&#xff1a;小北编程&#xff08;专注于HarmonyOS、Android、Java、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a; 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&#x1f…

Python图像处理实战:使用PIL库批量添加水印的完整指南【第27篇—python:Seaborn】

文章目录 1. 简介2. PIL库概述3. PIL库中涉及的类4. 实现原理5. 实现过程5.1 原始图片5.2 导入相关模块5.3 初始化数据5.4 水印字体设置5.5 打开原始图片并创建存储对象5.6 计算图片和水印的大小5.7 选择性设置水印文字5.8 绘制文字并设置透明度5.9 遍历获取图片文件并调用绘制…