如何实现基于ESP32的MQTT连接AWS设备稳定运行并避免锁定
ESP32 AWS IoT Core 连接稳定性问题排查与解决方案需求
设备基础信息
- 硬件:ESP32 WROOM开发板
- 开发环境:VS Code + PlatformIO,基于Arduino框架
- 核心依赖库:Arduino、WiFiClientSecure、MQTTClient、ArduinoJson、WiFi、time
- 业务逻辑:单设备通过专属主题每5-60秒向AWS IoT Core上报数据
- 供电方式:5V手机充电器
问题现象
设备运行一段时间后(无固定周期),AWS IoT Core停止接收设备上报的消息,但设备串口打印输出正常,且无法通过MQTT消息触发设备重启,必须手动复位才能恢复。需构建可靠解决方案,但无法长期进行串口调试,同时对MQTT遗嘱消息的用法存在疑问。
代码框架
#include <Arduino.h> #include <secret.h> //change #include <WiFiClientSecure.h> #include <MQTTClient.h> #include <ArduinoJson.h> #include <WiFi.h> #include "time.h" #define AWS_IOT_PUBLISH_TOPIC "topic/pub" //change #define AWS_IOT_SUBSCRIBE_TOPIC "topic/sub" //change const byte relay_gpio = 16; // the relay const char* ntpServer = "pool.ntp.org"; // timeserver const long gmtOffset_sec = 3600; const int daylightOffset_sec = 3600; int relayState = 0; String IoTID = "IoTID"; String sensorID = "IoTID_1"; //change WiFiClientSecure net = WiFiClientSecure(); MQTTClient client = MQTTClient(1024); void messageHandler(String &topic, String &payload) { Serial.println("alive"); // deserialize json StaticJsonDocument<200> doc; deserializeJson(doc, payload); String message = doc["message"]; Serial.println(message); if (message == "restart"){ ESP.restart(); } if (message == "remote_on"){ digitalWrite(relay_gpio, HIGH); } if (message == "remote_off"){ digitalWrite(relay_gpio, LOW); } } void connectAWS() { WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); Serial.println("Connecting to Wi-Fi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // Configure WiFiClientSecure to use the AWS IoT device credentials net.setCACert(AWS_CERT_CA); net.setCertificate(AWS_CERT_CRT); net.setPrivateKey(AWS_CERT_PRIVATE); // Connect to the MQTT broker on the AWS endpoint we defined earlier client.begin(AWS_IOT_ENDPOINT, 8883, net); // Create a message handler client.onMessage(messageHandler); Serial.println("Connecting to AWS IOT"); while (!client.connect(THINGNAME)) { Serial.print("."); delay(100); } if (!client.connected()) { Serial.println("AWS IoT Timeout!"); return; } // Subscribe to a topic client.setCleanSession(false); // That's one thing that was recommended client.subscribe(AWS_IOT_SUBSCRIBE_TOPIC); //client.setOptions(60, false, 2000); // I tried some of those, but with either none or negative effects Serial.println("AWS IoT Connected!"); } void publishMessage() { StaticJsonDocument<256> doc; doc["IoTID"] = IoTID; JsonObject meta_0 = doc["meta"].createNestedObject(); meta_0["SensorID"] = sensorID; meta_0["key"] = "XX"; meta_0["latitude"] = 12.345; meta_0["longitude"] = 67.890; meta_0["LocName"] = "Somewhere"; meta_0["TimeCET"] = time(NULL); JsonObject data_0 = doc["data"].createNestedObject(); data_0["switch_state"] = relayState; char jsonBuffer[512]; serializeJson(doc, jsonBuffer); client.publish(AWS_IOT_PUBLISH_TOPIC, jsonBuffer); } // void setup() { pinMode(relay_gpio, OUTPUT); Serial.begin(9600); configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); connectAWS(); //always connects. so far so good } void loop() { client.loop(); // Putting this delay(10); // and this at the beginning of the loop improved stability and was recommended relayState = digitalRead(relay_gpio); if (!client.connected()){ client.connect(THINGNAME); client.loop(); } client.onMessage(messageHandler); if (isnan(relayState)) { Serial.println("measurement error - waiting"); delay(5000); ESP.restart(); } lwmqtt_err_t lastError(); // for serial debugging lwmqtt_return_code_t returnCode(); // for serial debugging Serial.print(F("relayState: ")); Serial.print(relayState); Serial.print(F(", Timestamp:")); Serial.println(time(NULL)); if(time(NULL) > 1e9){ //make sure connection to timeserver is established publishMessage(); } delay(5000); }
已尝试的解决措施
- 替换MQTT库:从PubSubClient切换到MQTTClient,稳定性有所提升
- 优化循环逻辑:在
client.loop()后添加10ms延迟 - 调整JSON缓冲区大小
- 测试不同循环延迟:延迟越短,稳定性相对越好
- 添加定时自动重启:22小时自动重启,无改善
- 添加远程重启指令:仅在设备未出现连接锁定时有效
内容的提问来源于stack exchange,提问作者Chris Kn
相关产品推荐
相关产品推荐

