本项目实现了以下功能:
MQTT(Message Queuing Telemetry Transport)是一种轻量级的发布/订阅消息传输协议,专为资源受限设备和低带宽、高延迟网络设计。它具有以下特点:
在代码中,ESP32作为MQTT客户端既是发布者也是订阅者:
发布者角色:
aovalue
主题dovalue
主题订阅者角色:
switch
主题接收LED控制命令在本项目中,我们使用了安装在本地服务器(192.168.3.32)上的EMQX Broker。
特点:
安装方法:
# Docker安装(推荐)
docker pull emqx/emqx:latest
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx:latest
# Debian/Ubuntu
curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash
sudo apt-get install emqx
# CentOS/RHEL
curl -s https://assets.emqx.com/scripts/install-emqx-rpm.sh | sudo bash
sudo yum install emqx
基本配置:
通过访问http://localhost:18083(默认用户名和密码:admin/public)进行管理界面配置。
Mosquitto/HiveMQ/AWS IoT Cor
const char* mqtt_server = "192.168.*.32"; // MQTT服务器IP地址
// 定义引脚
const int ledPin = 2; // LED引脚
const int lightSensorPin = 34; // 光敏传感器的模拟引脚
const int tiltSensorPin = 5; // 倾斜传感器的数字引脚
WiFiClient espClient; // 创建WiFi客户端
PubSubClient client(espClient); // 创建MQTT客户端
void callback(char* topic, byte* payload, unsigned int length) {
// 将接收到的消息转换为字符串
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
// 判断主题是否为"switch"
if (String(topic) == "switch") {
// 根据消息内容控制LED
if (message == "ON") {
digitalWrite(ledPin, HIGH);
}
else if (message == "OFF") {
digitalWrite(ledPin, LOW);
}
}
}
// 每隔指定时间发布一次数据
if (now - lastMsg > publishInterval) {
lastMsg = now;
// 读取光敏传感器模拟值
int lightValue = analogRead(lightSensorPin);
// 读取倾斜传感器数字状态
int tiltState = digitalRead(tiltSensorPin);
// 发布光敏数据
char lightStr[10];
sprintf(lightStr, "%d", lightValue);
client.publish("aovalue", lightStr);
// 发布倾斜状态
char tiltStr[2];
sprintf(tiltStr, "%d", tiltState);
client.publish("dovalue", tiltStr);
}
本项目使用了三个TOPIC:
aovalue:模拟输出值(Analog Output Value)
dovalue:数字输出值(Digital Output Value)
switch:控制指令
这种主题设计简单明确,适合小型项目。在大型项目中,EMQX支持更复杂的主题结构和通配符订阅,如:
device/{deviceID}/{sensorType}/value
device/{deviceID}/control/{action}
连接阶段:
发布阶段:
订阅处理:
断线重连:
这个简单项目的基础技术可扩展到多种应用场景:
#include // ESP32的WiFi库
#include // MQTT客户端库
const char* ssid = "601B"; // WIFI名称
const char* password = "12345678"; // WIFI密码
const char* mqtt_server = "192.168.3.32"; // MQTT服务器IP地址
// 定义引脚
const int ledPin = 2; // LED引脚,ESP32内置LED通常在引脚2
const int lightSensorPin = 34; // 光敏传感器的模拟输入引脚,根据实际连接调整
const int tiltSensorPin = 5; // 倾斜传感器的数字输入引脚,根据实际连接调整
// 设置上次发布的时间
unsigned long lastMsg = 0;
const int publishInterval = 1000; // 发布频率(毫秒)
WiFiClient espClient; // 创建WiFi客户端对象
PubSubClient client(espClient); // 创建MQTT客户端对象
// 函数用于连接WiFi网络
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("WIFI连接到: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WIFI连接成功");
Serial.println("IP地址: ");
Serial.println(WiFi.localIP());
}
// 回调函数,当接收到订阅主题的消息时调用
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);
// 判断主题是否为"switch"
if (String(topic) == "switch") {
// 如果消息内容为"ON",打开LED
if (message == "ON") {
digitalWrite(ledPin, HIGH);
Serial.println("LED 已打开");
}
// 如果消息内容为"OFF",关闭LED
else if (message == "OFF") {
digitalWrite(ledPin, LOW);
Serial.println("LED 已关闭");
}
}
}
// 函数用于连接或重新连接到MQTT服务器
void reconnect() {
while (!client.connected()) {
Serial.println("正在尝试MQTT连接...");
// 创建随机客户端ID
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// 尝试连接
if (client.connect(clientId.c_str())) {
Serial.println("已连接到MQTT服务器");
// 成功连接后,订阅"switch"主题以控制LED
client.subscribe("switch");
Serial.println("已订阅主题: switch");
} else {
Serial.print("连接失败, 错误码=");
Serial.print(client.state());
Serial.println(",5秒后重试");
delay(5000);
}
}
}
void setup() {
// 初始化串口通信
Serial.begin(115200);
// 设置引脚模式
pinMode(ledPin, OUTPUT);
pinMode(tiltSensorPin, INPUT);
// 初始状态:LED关闭
digitalWrite(ledPin, LOW);
// 连接WiFi
setup_wifi();
// 设置MQTT服务器和回调函数
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
// 如果与MQTT服务器断开连接,重新连接
if (!client.connected()) {
reconnect();
}
// 处理MQTT消息
client.loop();
// 当前时间
unsigned long now = millis();
// 每隔指定时间发布一次数据
if (now - lastMsg > publishInterval) {
lastMsg = now;
// 读取光敏传感器数值(模拟值)
int lightValue = analogRead(lightSensorPin);
// 读取倾斜传感器状态(数字值)
int tiltState = digitalRead(tiltSensorPin);
// 将光敏传感器数值转换为字符串并发布
char lightStr[10];
sprintf(lightStr, "%d", lightValue);
client.publish("aovalue", lightStr);
Serial.print("发布光敏数据: ");
Serial.println(lightValue);
// 将倾斜传感器状态转换为字符串并发布
char tiltStr[2];
sprintf(tiltStr, "%d", tiltState);
client.publish("dovalue", tiltStr);
Serial.print("发布倾斜状态: ");
Serial.println(tiltState);
}
}