ESP32使用MQTT通信基础教程示例
硬件基础
这次使用的环境是https://wokwi.com/虚拟仿真平台
需要设备:ESP32S3,一个外部LED,一个电阻。
wokwi仿真平台环境搭建
1. 外观

{
"version": 1,
"author": "Anonymous maker",
"editor": "wokwi",
"parts": [
{ "type": "board-esp32-s3-devkitc-1", "id": "esp", "top": -9.78, "left": 110.17, "attrs": {} },
{ "type": "wokwi-led", "id": "led1", "top": 73.2, "left": -53.8, "attrs": { "color": "red" } },
{
"type": "wokwi-resistor",
"id": "r1",
"top": 13.55,
"left": -28.8,
"attrs": { "value": "1000" }
}
],
"connections": [
[ "esp:TX", "$serialMonitor:RX", "", [] ],
[ "esp:RX", "$serialMonitor:TX", "", [] ],
[ "led1:A", "r1:1", "green", [ "v0" ] ],
[ "led1:C", "esp:GND.1", "green", [ "v0" ] ],
[ "r1:2", "esp:12", "green", [ "v0" ] ]
],
"dependencies": {}
}
2. 程序代码
#include <WiFi.h>
#include <PubSubClient.h>
// ==================== WiFi配置 ====================
const char* ssid = "Wokwi-GUEST"; // Wokwi仿真WiFi名称
const char* password = ""; // Wokwi仿真WiFi密码(无密码)
const int wifiChannel = 6; // Wokwi使用的WiFi通道
const bool hiddenSSID = false; // 网络是否隐藏
// ==================== MQTT配置 ====================
const char* mqtt_server = "60.204.140.141"; // MQTT服务器
const int mqtt_port = 1883; // MQTT端口
const char* mqtt_user = "admin"; // 用户名
const char* mqtt_password = "plulic"; // 密码
// ==================== MQTT主题 ====================
const char* topic_led = "wokwi/test/led"; // LED控制主题
const char* topic_status = "wokwi/test/status"; // 状态主题
// ==================== 硬件引脚定义 ====================
const int LED_PIN = 12; // LED引脚 GPIO12
const int INTERNAL_LED = 2; // ESP32内置LED (GPIO2),避免使用BUILTIN_LED
// ==================== 全局对象 ====================
WiFiClient espClient;
PubSubClient client(espClient);
// ==================== 全局变量 ====================
bool ledState = false; // LED状态 (true=开, false=关)
bool wifiConnected = false; // WiFi连接状态
unsigned long lastReconnectAttempt = 0;
const unsigned long reconnectInterval = 3000;
unsigned long lastHeartbeat = 0;
const unsigned long heartbeatInterval = 5000;
// ==================== 函数声明 ====================
void setupWiFi();
void connectToWiFi();
void mqttCallback(char* topic, byte* payload, unsigned int length);
boolean reconnectMQTT();
void controlLED(bool state);
void blinkLED(int pin, int times, int delayTime);
void publishStatus();
void printWiFiStatus();
// ==================== 初始化设置 ====================
void setup() {
Serial.begin(115200);
delay(1000); // 等待串口初始化
Serial.println("\\n==========================================");
Serial.println(" ESP32 Wokwi仿真 – MQTT LED控制测试");
Serial.println("==========================================");
// 设置引脚模式
pinMode(LED_PIN, OUTPUT);
pinMode(INTERNAL_LED, OUTPUT);
digitalWrite(LED_PIN, LOW);
digitalWrite(INTERNAL_LED, LOW);
// 闪烁LED表示开始启动
blinkLED(INTERNAL_LED, 2, 200);
// 设置WiFi和MQTT
setupWiFi();
Serial.println("\\n✅ 系统初始化完成!");
Serial.println("📡 MQTT控制命令:");
Serial.println(" 主题: wokwi/test/led");
Serial.println(" 消息: on – 打开LED");
Serial.println(" 消息: off – 关闭LED");
Serial.println(" 消息: toggle – 切换LED状态");
Serial.println(" 消息: blink – LED闪烁3次");
Serial.println("==========================================");
}
// ==================== WiFi设置函数 ====================
void setupWiFi() {
Serial.println("\\n🔧 配置WiFi连接…");
Serial.print("WiFi网络: ");
Serial.println(ssid);
Serial.print("WiFi通道: ");
Serial.println(wifiChannel);
// 在Wokwi中,可以尝试设置WiFi配置
WiFi.mode(WIFI_STA);
// 开始连接WiFi
connectToWiFi();
}
// ==================== WiFi连接函数 ====================
void connectToWiFi() {
Serial.print("🔗 连接WiFi…");
// 断开之前的连接
WiFi.disconnect(true);
delay(100);
// 开始连接
WiFi.begin(ssid, password);
// 等待连接,带超时
unsigned long startTime = millis();
const unsigned long timeout = 15000; // 15秒超时
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
// 闪烁内置LED表示连接中
digitalWrite(INTERNAL_LED, !digitalRead(INTERNAL_LED));
// 检查超时
if (millis() – startTime > timeout) {
Serial.println("\\n❌ WiFi连接超时!");
Serial.println("可能的原因:");
Serial.println("1. 不在Wokwi仿真环境中");
Serial.println("2. WiFi名称或密码错误");
Serial.println("3. 网络配置问题");
// 慢闪表示失败
while (true) {
digitalWrite(INTERNAL_LED, HIGH);
delay(300);
digitalWrite(INTERNAL_LED, LOW);
delay(700);
}
}
}
Serial.println("\\n✅ WiFi连接成功!");
wifiConnected = true;
// 显示WiFi状态
printWiFiStatus();
// 快速闪烁表示成功
blinkLED(INTERNAL_LED, 3, 100);
// 设置MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(mqttCallback);
// 初始化MQTT连接
reconnectMQTT();
}
// ==================== 打印WiFi状态 ====================
void printWiFiStatus() {
Serial.println("\\n📡 WiFi连接信息:");
Serial.print(" SSID: ");
Serial.println(WiFi.SSID());
Serial.print(" IP地址: ");
Serial.println(WiFi.localIP());
Serial.print(" MAC地址: ");
Serial.println(WiFi.macAddress());
Serial.print(" 信号强度: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
Serial.print(" 子网掩码: ");
Serial.println(WiFi.subnetMask());
Serial.print(" 网关: ");
Serial.println(WiFi.gatewayIP());
Serial.print(" DNS服务器: ");
Serial.println(WiFi.dnsIP());
}
// ==================== MQTT回调函数 ====================
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("📨 收到MQTT消息 [");
Serial.print(topic);
Serial.print("]: ");
// 将消息转换为字符串
String message;
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// 处理LED控制消息
if (String(topic) == topic_led) {
if (message == "on") {
controlLED(true);
client.publish(topic_status, "LED已打开");
}
else if (message == "off") {
controlLED(false);
client.publish(topic_status, "LED已关闭");
}
else if (message == "toggle") {
ledState = !ledState;
controlLED(ledState);
String status = ledState ? "LED已打开" : "LED已关闭";
client.publish(topic_status, status.c_str());
}
else if (message == "blink") {
blinkLED(LED_PIN, 3, 200);
client.publish(topic_status, "LED已闪烁3次");
}
else if (message == "status") {
publishStatus();
}
else {
String errorMsg = "未知命令: " + message;
client.publish(topic_status, errorMsg.c_str());
Serial.println("❌ 未知LED命令");
}
}
}
// ==================== MQTT重连函数 ====================
boolean reconnectMQTT() {
if (!wifiConnected) {
Serial.println("❌ WiFi未连接,无法连接MQTT");
return false;
}
Serial.print("🔗 连接MQTT服务器… ");
// 生成唯一的客户端ID
String clientId = "Wokwi-ESP32-";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
Serial.println("✅ 连接成功!");
// 订阅主题
client.subscribe(topic_led);
Serial.print(" 订阅主题: ");
Serial.println(topic_led);
// 发布连接成功消息
String connectMsg = "设备已连接 – IP: " + WiFi.localIP().toString();
client.publish(topic_status, connectMsg.c_str());
// 发布初始状态
publishStatus();
// 闪烁表示成功
blinkLED(INTERNAL_LED, 2, 150);
return true;
} else {
Serial.print("❌ 连接失败, 错误码: ");
Serial.println(client.state());
return false;
}
}
// ==================== 主循环 ====================
void loop() {
// 检查WiFi连接
if (WiFi.status() != WL_CONNECTED) {
if (wifiConnected) {
Serial.println("⚠️ WiFi连接丢失!");
wifiConnected = false;
digitalWrite(INTERNAL_LED, LOW);
}
// 慢闪表示WiFi断开
static unsigned long lastBlink = 0;
if (millis() – lastBlink > 1000) {
lastBlink = millis();
digitalWrite(INTERNAL_LED, !digitalRead(INTERNAL_LED));
}
// 每10秒尝试重连
static unsigned long lastReconnect = 0;
if (millis() – lastReconnect > 10000) {
lastReconnect = millis();
Serial.println("🔄 尝试重新连接WiFi…");
connectToWiFi();
}
delay(100);
return;
}
// WiFi已连接
if (!wifiConnected) {
wifiConnected = true;
Serial.println("✅ WiFi重新连接成功!");
printWiFiStatus();
}
// 检查MQTT连接
if (!client.connected()) {
unsigned long now = millis();
if (now – lastReconnectAttempt > reconnectInterval) {
lastReconnectAttempt = now;
reconnectMQTT();
}
} else {
client.loop();
}
// 发送心跳(每5秒)
if (millis() – lastHeartbeat > heartbeatInterval && client.connected()) {
lastHeartbeat = millis();
// 发送简单的心跳
String heartbeat = "{\\"device\\":\\"Wokwi-ESP32\\",\\"uptime\\":" + String(millis() / 1000) + ",\\"led\\":" + String(ledState) + "}";
client.publish("wokwi/test/heartbeat", heartbeat.c_str());
// 快速闪烁表示活跃
digitalWrite(INTERNAL_LED, HIGH);
delay(10);
digitalWrite(INTERNAL_LED, LOW);
}
delay(10);
}
// ==================== 控制LED函数 ====================
void controlLED(bool state) {
ledState = state;
digitalWrite(LED_PIN, state ? HIGH : LOW);
Serial.print("💡 LED ");
Serial.println(state ? "已打开" : "已关闭");
// 视觉反馈
digitalWrite(INTERNAL_LED, HIGH);
delay(50);
digitalWrite(INTERNAL_LED, LOW);
}
// ==================== 闪烁LED函数 ====================
void blinkLED(int pin, int times, int delayTime) {
Serial.print("✨ 闪烁");
if (pin == LED_PIN) Serial.print("外部");
else if (pin == INTERNAL_LED) Serial.print("内置");
Serial.print("LED ");
Serial.print(times);
Serial.println(" 次");
for (int i = 0; i < times; i++) {
digitalWrite(pin, HIGH);
delay(delayTime);
digitalWrite(pin, LOW);
if (i < times – 1) {
delay(delayTime);
}
}
}
// ==================== 发布状态函数 ====================
void publishStatus() {
if (client.connected()) {
// 构建JSON状态字符串
String status = "{";
status += "\\"led\\":" + String(ledState ? "true" : "false") + ",";
status += "\\"wifi_rssi\\":" + String(WiFi.RSSI()) + ",";
status += "\\"ip\\":\\"" + WiFi.localIP().toString() + "\\",";
status += "\\"free_heap\\":" + String(esp_get_free_heap_size()) + ",";
status += "\\"uptime\\":" + String(millis() / 1000) + ",";
status += "\\"name\\":\\"杨同学\\""; // 注意:这里需要双引号
status += "}";
client.publish(topic_status, status.c_str());
Serial.println("📤 已发布系统状态");
Serial.println(status);
}
}
MQTT服务器的搭建
MQTT 服务可以用公共的服务器:如果您无需自行部署 MQTT 服务,您可以使用 EMQX 提供的在线公开版本进行快速测试:
Broker 地址: broker.emqx.io
Broker TCP 端口: 1883
Broker SSL 端口: 8883
下面是自己创建MQTT的服务器教程
主播这里用的docker安装,如果没有下载docker可以下载一个
1.安装MQTT
docker run -d –name emqx \\
-p 0.0.0.0:18083:18083 \\
-p 0.0.0.0:1883:1883 \\
-p 0.0.0.0:8083:8083 \\
-p 0.0.0.0:8883:8883 \\
-p 0.0.0.0:8084:8084 \\
-e EMQX_DASHBOARD__LISTENER__HTTP__BIND=0.0.0.0:18083 \\
emqx/emqx
注意需要开通对应端口,否则访问不了服务
访问服务:http://60.204.140.141:18083/ 这里60.204.140.141你的服务器IP,这里第一次进入需要账号密码:admin/public

2.安装mqttx-web
当然也可以不安装网页版的客户端,可以直接下载window版本的客户端:MQTTX:全功能 MQTT 客户端工具
docker run -d –name mqttx-web -p 88:80 emqx/mqttx-web
访问服务mqttx-web:http://60.204.140.141:88/ 这里60.204.140.141你的服务器IP,第一次进入会让你连接MQTT服务器,主播连过了就没有了

开始使用:
1.连接MQTT服务器

2.连接订阅
const char* topic_led = "wokwi/test/led"; // LED控制主题
const char* topic_status = "wokwi/test/status"; // 状态主题
有两个主题一个控制的:wokwi/test/led,一个状态的:wokwi/test/status,这里wokwi/test/led订阅发送的指令,esp32接收到处理完后会将信息反馈到wokwi/test/status订阅中。
下面开始连接:一共有两个主题都要连接


2.发送指令
首先要启动仿真平台

打开MQTTX软件

3.接收指令并返回状态
当wokwi/test/led订阅发送指令。仿真平台的esp32会接收并处理指令,然后再返回状态

结尾
🆗,到此结束,主播是计算机科学与技术专业的之前都是学软件开发的,也是刚刚学嵌入式,对硬件不是很了解,如有错误,请谅解,共同学习~,后面会出一期编写手机APP控制灯的开关教程。
网硕互联帮助中心






评论前必须登录!
注册