当前位置: 首页 > article >正文

【ESP32】ESP32物联网应用:MQTT控制与状态监测

ESP32物联网应用:MQTT控制与状态监测

引言

在物联网时代,远程监测和控制设备已经成为现实生活中常见的需求。本文将介绍如何使用ESP32微控制器配合MQTT协议,实现一个简单而强大的物联网应用:远程状态监测和设备控制。我们将以巴法云平台为例,展示如何通过互联网随时随地监控和控制家中的电器设备。

项目概述

本项目实现了以下功能:

  1. 状态监测:通过GPIO4引脚读取外部开关状态,并将状态实时上传到云平台
  2. 远程控制:通过MQTT订阅消息,远程控制GPIO2引脚的高低电平(可连接继电器控制电器)
  3. 供电输出:GPIO32引脚始终保持高电平,为外接设备供电

这样的设计可以应用于智能家居控制、远程设备监测和自动化控制系统等多种场景。

硬件准备

本项目需要以下硬件:

  • ESP32开发板(如NodeMCU-32S、WROOM-32等)
  • 面包板和连接线
  • 输入开关(连接到GPIO4)
  • LED指示灯或继电器(连接到GPIO2)
  • 可选:需要3.3V供电的传感器或模块(连接到GPIO32)

软件环境

  • Arduino IDE
  • PubSubClient库(MQTT客户端)
  • WiFi库(已包含在ESP32开发板包中)

核心代码解析

1. 初始化与配置

首先,我们需要引入必要的库并配置WiFi和MQTT连接信息:

#include <WiFi.h>         // ESP32 WiFi库
#include <PubSubClient.h> // MQTT客户端库// WiFi配置
const char *ssid = "601B";      // WiFi名称
const char *password = "12345678"; // WiFi密码// MQTT服务器配置
const char* mqtt_server = "bemfa.com";    // MQTT服务器地址
const int mqtt_server_port = 9501;        // MQTT服务器端口
#define ID_MQTT "0c876e1774cc3bd27de1d5d1bfc61c90" // 客户端ID

这部分代码设置了我们的WiFi连接参数和MQTT服务器信息。巴法云是一个免费的物联网平台,提供MQTT服务,使我们能够轻松实现设备间的通信。

2. 引脚定义与功能分配

// 定义引脚
#define SWITCH_PIN 4      // 开关连接的GPIO引脚
#define OUTPUT_PIN_D2 2   // D2引脚,根据MQTT消息控制
#define OUTPUT_PIN_D32 32 // D32引脚,保持高电平

我们使用三个GPIO引脚,各自负责不同的功能:

  • GPIO4:读取外部开关状态
  • GPIO2:由MQTT消息控制的输出引脚
  • GPIO32:始终保持高电平的电源输出引脚

3. MQTT消息处理回调函数

void callback(char* topic, byte* payload, unsigned int length) {// 将接收到的字节数组转换为字符串String message;for (int i = 0; i < length; i++) {message += (char)payload[i];}// 根据接收到的消息控制D2引脚if (String(topic) == mqtt_sub_topic) {if (message == "ON") {digitalWrite(OUTPUT_PIN_D2, HIGH);Serial.println("D2引脚设置为高电平");} else if (message == "OFF") {digitalWrite(OUTPUT_PIN_D2, LOW);Serial.println("D2引脚设置为低电平");}}
}

这个回调函数是实现远程控制的核心。当ESP32收到MQTT消息时,会触发此函数。如果消息内容是"ON",则将D2引脚设为高电平;如果是"OFF",则设为低电平。这样,我们就可以通过手机或电脑发送指令来控制连接到D2引脚的设备。

4. 主循环中的状态监测与发布

void loop() {// 检查MQTT连接状态if (!client.connected()) {reconnect();}// 处理MQTT消息client.loop();// 读取开关状态bool val = digitalRead(SWITCH_PIN);// 限制发布频率static unsigned long lastPublishTime = 0;if (millis() - lastPublishTime > 500) {lastPublishTime = millis();// 发布开关状态到MQTTif (val == 0) {client.publish(mqtt_pub_topic, "OFF");} else {client.publish(mqtt_pub_topic, "ON");}}// 确保D32保持高电平digitalWrite(OUTPUT_PIN_D32, HIGH);
}

在主循环中,我们持续监测连接到GPIO4的开关状态,并将其发布到MQTT主题"sendiot"。为了避免消息发送过于频繁,我们限制了发布频率,每500毫秒最多发布一次。同时,我们确保GPIO32始终保持高电平,为需要稳定电源的外接设备供电。

#include <WiFi.h>         // ESP32 WiFi库
#include <PubSubClient.h> // MQTT客户端库// WiFi配置
const char *ssid = "601B";      // WiFi名称
const char *password = "12345678"; // WiFi密码// MQTT服务器配置
const char* mqtt_server = "bemfa.com";    // MQTT服务器地址
const int mqtt_server_port = 9501;        // MQTT服务器端口
#define ID_MQTT "0c876e1774cc3bd27de1d5d1bfc61c90" // 您的客户端ID// 创建WiFi和MQTT客户端实例
WiFiClient espClient;
PubSubClient client(espClient);// 定义引脚
#define SWITCH_PIN 4      // 开关连接的GPIO引脚
#define OUTPUT_PIN_D2 2   // D2引脚,根据MQTT消息控制
#define OUTPUT_PIN_D32 32 // D32引脚,保持高电平// MQTT主题
const char* mqtt_sub_topic = "reciot";  // 订阅的主题
const char* mqtt_pub_topic = "sendiot"; // 发布的主题// WiFi连接函数
void setup_wifi() {  delay(10);  Serial.println();  Serial.print("Connecting to ");  Serial.println(ssid);  WiFi.begin(ssid, password);  while (WiFi.status() != WL_CONNECTED) {  delay(500);  Serial.print(".");  }  Serial.println("");  Serial.println("WiFi connected");  Serial.print("IP address: ");  Serial.println(WiFi.localIP());  
}  // 重连函数
void reconnect() {// 循环直到重新连接while (!client.connected()) {Serial.print("尝试连接MQTT...");// 尝试连接if (client.connect(ID_MQTT)) {Serial.println("connected");// 连接成功后,订阅主题并检查结果boolean subResult = client.subscribe(mqtt_sub_topic);if(subResult) {Serial.print("订阅主题成功: ");Serial.println(mqtt_sub_topic);} else {Serial.print("订阅主题失败: ");Serial.println(mqtt_sub_topic);}} else {Serial.print("failed, rc=");Serial.print(client.state());Serial.println(" try again in 5 seconds");delay(1000);}}
}// MQTT消息接收回调函数
void callback(char* topic, byte* payload, unsigned int length) {Serial.print("订阅的信息为 [");Serial.print(topic);Serial.print("] ");// 将接收到的字节数组转换为字符串String message;for (int i = 0; i < length; i++) {message += (char)payload[i];}Serial.println(message);Serial.println("*** 收到MQTT消息!***");// 根据接收到的消息控制D2引脚if (String(topic) == mqtt_sub_topic) {if (message == "ON") {digitalWrite(OUTPUT_PIN_D2, HIGH);Serial.println("D2引脚设置为高电平");} else if (message == "OFF") {digitalWrite(OUTPUT_PIN_D2, LOW);Serial.println("D2引脚设置为低电平");}}
}void setup() {// 初始化串口Serial.begin(115200);// 设置引脚模式pinMode(SWITCH_PIN, INPUT);pinMode(OUTPUT_PIN_D2, OUTPUT);pinMode(OUTPUT_PIN_D32, OUTPUT);// 将D32设置为高电平digitalWrite(OUTPUT_PIN_D32, HIGH);Serial.println("D32引脚已设置为高电平");// 初始化D2为低电平digitalWrite(OUTPUT_PIN_D2, LOW);Serial.println("D2引脚初始化为低电平");// 连接WiFisetup_wifi();// 设置MQTT服务器和回调client.setServer(mqtt_server, mqtt_server_port);client.setCallback(callback);// 连接MQTT服务器并订阅主题reconnect();// 设置完成提示Serial.println("设置完成,ESP32已准备就绪");
}void loop() {// 检查MQTT连接状态if (!client.connected()) {Serial.println("MQTT连接断开,正在重连...");reconnect();}// 处理MQTT消息client.loop();// 读取开关状态bool val = digitalRead(SWITCH_PIN);// 限制发布频率static unsigned long lastPublishTime = 0;if (millis() - lastPublishTime > 500) {lastPublishTime = millis();// 发布开关状态到MQTTif (val == 0) {Serial.println("发布: OFF");client.publish(mqtt_pub_topic, "OFF");} else {Serial.println("发布: ON");client.publish(mqtt_pub_topic, "ON");}}// 循环延时delay(100);// 确保D32保持高电平digitalWrite(OUTPUT_PIN_D32, HIGH);
}

实际应用场景

这个项目可以应用于多种物联网场景:

  1. 智能照明

    • GPIO4连接墙壁开关
    • GPIO2连接继电器控制灯泡
    • 手机APP可远程控制灯光,同时看到墙壁开关的状态
  2. 智能插座

    • GPIO2控制继电器,切换电源
    • 手机可随时查看和控制插座的开关状态
  3. 安防系统

    • GPIO4连接门磁传感器
    • 当门打开时,传感器状态变化会通过MQTT发送到云端
    • 手机APP可接收实时通知
  4. 农业监测

    • GPIO4连接土壤湿度传感器
    • GPIO2控制灌溉系统
    • 可设置自动或手动控制灌溉

优化与扩展

本项目还可以进行以下扩展:

  1. 添加多个传感器

    • 利用ESP32的其他GPIO引脚,连接温度、湿度、光线等传感器
    • 增加数据发布的维度
  2. 增加本地控制界面

    • 添加OLED显示屏展示当前状态
    • 添加按钮实现本地控制
  3. 实现条件触发

    • 添加逻辑判断,根据传感器数据自动控制输出
    • 例如,当检测到湿度过低时自动开启灌溉系统

相关文章:

【ESP32】ESP32物联网应用:MQTT控制与状态监测

ESP32物联网应用&#xff1a;MQTT控制与状态监测 引言 在物联网时代&#xff0c;远程监测和控制设备已经成为现实生活中常见的需求。本文将介绍如何使用ESP32微控制器配合MQTT协议&#xff0c;实现一个简单而强大的物联网应用&#xff1a;远程状态监测和设备控制。我们将以巴…...

RabbitMQ运维

RabbitMQ运维 一.集群1.简单介绍2.集群的作用 二.搭建集群1.多机多节点搭建步骤 2.单机单节点搭建步骤 3.宕机演示 三.仲裁队列1.简单介绍2.Raft协议Raft基本概念主节点选举选举过程 3.仲裁队列的使用 四.HAProxy负载均衡1.安装HAProxy2.HAProxy的使用 一.集群 1.简单介绍 Ra…...

Ansible 实战:Roles,运维的 “魔法函数”

一、介绍 你现在已经学过tasks和handlers&#xff0c;那么&#xff0c;最好的playbook组织方式是什么呢&#xff1f;答案很简单&#xff1a;使用roles&#xff01;roles基于一种已知的文件结构&#xff0c;能够自动加载特定的vars_files、tasks以及handlers。通过roles对内容进…...

CVAT安装和使用(Windows)

必要组件安装 WSL2 Docker Git Chrome Install WSL2 (Windows subsystem for Linux) refer to this official guide. WSL2 requires Windows 10, version 2004 or higher. After installing WSL2, install a Linux Distribution of your choice. 安装 WSL2&#xff08;适用…...

Spring 中的 bean 生命周期

&#x1f331; 一、什么是 Bean 生命周期&#xff1f; 在 Spring 容器中&#xff0c;一个 Bean 从“创建 → 初始化 → 使用 → 销毁”&#xff0c;经历了完整的生命周期。 Spring 提供了 多个扩展点 让你可以在这些阶段做事情&#xff0c;比如注入资源、日志记录、连接资源、清…...

关于JVM和OS中的指令重排以及JIT优化

关于JVM和OS中的指令重排以及JIT优化 前言&#xff1a; 这东西应该很重要才对&#xff0c;可是大多数博客都是以讹传讹&#xff0c;全是错误&#xff0c;尤其是JVM会对字节码进行重排都出来了&#xff0c;明明自己测一测就出来的东西&#xff0c;写出来误人子弟… 研究了两天&…...

微软推出首款量子计算芯片Majorana 1

全球首款拓扑架构量子芯片问世&#xff0c;2025年2月20日&#xff0c;经过近20年研究&#xff0c;微软推出了首款量子计算芯片Majorana 1&#xff0c;其宣传视频如本文末尾所示。 微软表示&#xff0c;开发Majorana 1需要创造一种全新的物质状态&#xff0c;即所谓的“拓扑体”…...

数组练习题总结

一、求出数组中的最大值let arr [1, 2, 5, 7];let max 0;for (i 0; i < arr.length; i) {// console.log(max);if (max < arr[i]) {max arr[i];}}console.log(max); 首先生成一个数组&#xff0c;设一个变量为保存最大值&#xff0c;写一个循环&#xff0c;在循环里写…...

Kotlin 中的 `reified` 关键字全解析:保留类型信息 + 优化高阶函数的双重魔法

在使用 Kotlin 编写泛型函数时&#xff0c;你是否遇到过这样的尴尬&#xff1a;你想判断某个对象是不是泛型类型 T&#xff0c;结果却发现代码根本编译不过&#xff1f;这是因为 Kotlin 和 Java 一样&#xff0c;泛型在运行时会被类型擦除。 为了解决这个问题&#xff0c;Kotl…...

在CPU服务器上部署Ollama和Dify的过程记录

在本指南中&#xff0c;我将详细介绍如何在CPU服务器上安装和配置Ollama模型服务和Dify平台&#xff0c;以及如何利用Docker实现这些服务的高效部署和迁移。本文分为三大部分&#xff1a;Ollama部署、Dify环境配置和Docker环境管理&#xff0c;适合需要在本地或私有环境中运行A…...

【计网】TCP 协议详解 与 常见面试题

三次握手、四次挥手的常见面试题 不用死记&#xff0c;只需要清楚三次握手&#xff0c;四次挥手的流程&#xff0c;回答的时候心里要记住&#xff0c;假设网络是不可靠的 问题(1)&#xff1a;为什么关闭连接时需要四次挥手&#xff0c;而建立连接却只要三次握手&#xff1f; 关…...

Java 基础-31-枚举-认识枚举

在Java编程语言中&#xff0c;枚举&#xff08;Enum&#xff09;是一种特殊的类&#xff0c;它允许一组固定的常量。它们非常适合用来表示一组固定的值&#xff0c;比如星期几、季节、颜色等。枚举自Java 5开始引入&#xff0c;为定义常量提供了一种更强大和方便的方式。本文将…...

7.4 SVD 的几何背景

一、SVD 的几何解释 SVD 将矩阵分解成三个矩阵的乘积&#xff1a; ( 正交矩阵 ) ( 对角矩阵 ) ( 正交矩阵 ) (\pmb{正交矩阵})\times(\pmb{对角矩阵})(\pmb{正交矩阵}) (正交矩阵)(对角矩阵)(正交矩阵)&#xff0c;用几何语言表述其几何背景&#xff1a; ( 旋转 ) ( 伸缩 )…...

低延迟云网络的核心技术

低延迟云网络通过架构优化、协议创新、硬件加速等多维度技术手段,将数据传输延迟降低至毫秒级甚至微秒级。 1. 网络架构优化 1.1 扁平化网络Leaf-Spine 架构 减少网络层级,缩短数据转发路径(如数据中心内部一跳可达)。 扁平化网络Leaf-Spine(叶子-脊椎)架构是一种现代…...

C++的多态-上

目录 多态的概念 多态的定义及实现 1.虚函数 2. 多态的实现 2.1.多态构成条件 2.2.虚函数重写的两个例外 (1)协变(基类与派生类虚函数返回值类型不同) (2)析构函数的重写(基类与派生类析构函数的名字不同) 2.3.多态的实现 2.4.多态在析构函数中的应用 2.5.多态构成条…...

内存与显存:从同根生到殊途异路的科技演进

在现代计算机的世界里&#xff0c;内存和显存是两个不可或缺的硬件组件。它们看似功能相近&#xff0c;却在发展历程中逐渐分道扬镳&#xff0c;各自服务于不同的计算需求。今天&#xff0c;我们将从一根内存条和一块显卡入手&#xff0c;深入探讨内存与显存的异同&#xff0c;…...

手搓多模态-04 归一化介绍

在机器学习中&#xff0c;归一化是一个非常重要的工具&#xff0c;它能帮助我们加速训练的速度。在我们前面的SiglipVisionTransformer 中&#xff0c;也有用到归一化层&#xff0c;如下代码所示&#xff1a; class SiglipVisionTransformer(nn.Module): ##视觉模型的第二层&am…...

【C++】第八节—string类(上)——详解+代码示例

hello&#xff0c;又见面了&#xff01; 云边有个稻草人-CSDN博客 C_云边有个稻草人的博客-CSDN博客——C专栏&#xff08;质量分高达97&#xff01;&#xff09; 菜鸟进化中。。。 目录 一、为什么要学习string类&#xff1f; 1.1 C语言中的字符串 1.2 面试题(暂不做讲解) …...

Java 数组与 ArrayList 核心区别解析:从源码到实战!!!

&#x1f31f; Java 数组与 ArrayList 核心区别解析&#xff1a;从源码到实战 &#x1f4a1; Java 开发者必读&#xff01; 数组&#xff08;Array&#xff09;和 ArrayList 是 Java 中最常用的数据存储结构&#xff0c;但它们的底层设计、性能表现和适用场景差异显著。本文通…...

【易飞】易飞批量选择品号处理方法,工作效率提升300%

开窗选择品号方式要么手动输入,要么以什么开头、包含、从A物料到B物料查询后返回的有规律的品号。对于没有规律且大量品号的处理方式是否有便捷的方法呢? 尤其在通常在查询多阶材料清单,查询库存明细表,整批变更元件等如品号无规律情况下,只能一个个选择,无法通过EXCEL方…...

【最新版】啦啦外卖v64系统独立版源码+全部小程序APP端+安装教程

一.系统介绍 啦啦外卖跑腿平台独立版&#xff0c;使用的都知道该系统功能非常强大&#xff0c;应该说是目前外卖平台功能最全的一套系统。主要是功能非常多&#xff0c;拿来即用&#xff0c;包括客户端小程序、配送端小程序、商户端小程序&#xff0c;还有对应四个端的APP源码…...

iproute2 工具集使用详解

目录 一、iproute2 核心命令&#xff1a;ip二、常用功能详解1. 管理网络接口&#xff08;link 对象&#xff09;2. 管理 IP 地址&#xff08;address 对象&#xff09;3. 管理路由表&#xff08;route 对象&#xff09;4. 管理 ARP 和邻居缓存&#xff08;neigh 对象&#xff0…...

项目总结之常问的一些问题

1.项目功能介绍&#xff0c;重难点 重难点&#xff1a; mock工具使用&#xff08;涉及到的三方接口过多&#xff0c;由于网络等原因无法调通&#xff0c;所以测试的时候&#xff0c;采用mock工具来模拟返回接口真正调用后响应数据&#xff09; 2.项目负责哪部分&#xff1f;…...

C语言查漏补缺:占位符篇

占位符篇 1. 整数类型2. 字符类型3. 浮点数类型4. 指针类型5. 字符串6. 修饰符 1. 整数类型 %d / %i&#xff1a;用于 int&#xff08;有符号十进制整数&#xff09;。int num -42; printf("%d", num); // 输出: -42%u&#xff1a;用于 unsigned int&#xff08;无…...

cut命令用法

cut 是 Linux/Unix 系统中一个用于按列提取文本内容的命令&#xff0c;常用于处理结构化文本&#xff08;如 CSV、日志、配置文件等&#xff09;。它通过分隔符、字符位置或字节位置来切割文本&#xff0c;提取指定部分。 核心功能 按字段&#xff08;列&#xff09;提取&#…...

java 正则表达式优化

1&#xff0c;什么是正则表达式 正则表达式使用一些特定的元字符来检索、匹配以及替换符合规则的字符串。 构造正则表达式语法的元字符&#xff0c;由普通字符、标准字符、限定字符&#xff08;量词&#xff09;、定位字符&#xff08;边界字符&#xff09;组成 普通字符 字母[…...

AD(Altium Designer)更换PCB文件的器件封装

一、确定是否拥有想换的器件PCB封装 1.1 打开现有的原理图 1.2 确定是否拥有想换的器件PCB文件 1.2.1 如果有 按照1.3进行切换器件PCB封装 1.2.2 如果没有 按照如下链接进行添加 AD(Altium Designer)已有封装库的基础上添加器件封装-CSDN博客https://blog.csdn.net/XU15…...

【文献研究】含硼钢中BN表面偏析对可镀性的影响

《B 添加钢的溶融 Zn めっき性に及ぼす BN 表面析出の影響》由JFE公司田原大輔等人撰写。研究聚焦 B 添加钢在低露点退火时 BN 形成对镀锌性的影响&#xff0c;对汽车用高强度钢镀锌工艺优化意义重大。通过多组对比实验&#xff0c;结合多种分析手段&#xff0c;明确了相关因素…...

React学习-css

W3Schools Tryit Editor CSS 教程 CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明: p { /* 这是个注释 */ color:red; text-align:center; }选择器 CSS Id: #para1{ text-align:center; color:red; } Class: .center {text-align:center;} p…...

AIP-215 API特定proto

编号215原文链接AIP-215: API-specific protos状态批准创建日期2018-10-01更新日期2018-10-01 API通常使用API特定proto定义&#xff0c;偶尔依赖通用组件。保持API相互隔离可以避免版本问题和客户端库打包问题。 指南 所有特定于某个API的protos 必须 位于带有主版本号的包…...