我的应用程序有一段时间遇到了一些麻烦,无法弄清楚为什么 ESP32 会卡在处理链中。该问题在生产模式下 3 或 4 周后随机发生。有时1周后。很难说。
首先,让我解释一下流程链是怎样的。
ESP 启动时,MQTT 客户端 (AsyncMQTT_Generic Library) 连接到 MQTT 代理 Mosquitto,订阅主题
esp/config/<ESP32_WIFI_MAC_ADDRESS>
,接收 JSON 对象形式的消息负载
{"idsl":900000000,"dsle":true,"ihttp":1800000,"time":1712487701726,"addr":["C4:7C:8D:6D:31:2A"],"syse":true}
通过ArduinoJson(版本6.21.5)反序列化并存储到ESP32的RTC存储
rtcConfig
,如下:
#define MAC_ADDR_LENGTH 18
#define MAX_BLE_NUMBER 5
const char* MQTT_TOPIC_CONFIG = "esp/config/";
char* topicConfigMac;
struct RtcData {
unsigned int wakeupCnt;
uint32_t channel;
uint8_t bssid[6];
uint8_t systemEnabled;
uint8_t deepSleepEnabled;
uint64_t deepSleepInterv;
uint32_t httpRequestInterv;
uint8_t hasConfig;
uint64_t time;
char bleAddr[MAX_BLE_NUMBER][MAC_ADDR_LENGTH];
};
// Real Time Clock memory
RTC_DATA_ATTR RtcData rtcConfig;
StaticJsonDocument<512> jsonConfig;
// Receiving MQTT message from topic
void onMqttMessage(char* topic, char* payload, const AsyncMqttClientMessageProperties& properties,
const size_t& len, const size_t& index, const size_t& total) {
Serial.printf("MQTT received message on topic '%s'\n", topic);
Serial.printf(" QoS: %u", properties.qos);
Serial.printf(", dup: %d", properties.dup);
Serial.printf(", retain: %d", properties.retain);
Serial.printf(", len: %u", len);
Serial.printf(", index: %u", index);
Serial.printf(", total: %u\n", total);
if (strcmp(topic, topicConfigMac) == 0) {
deserializePayload(payload);
} else {
Serial.printf("MQTT received message topic %s is unequal to %s\n", topic, topicConfigMac);
enterSleepMode();
}
}
void deserializePayload(char* payload) {
Serial.print("Deserialize payload: ");
jsonConfig.clear();
DeserializationError error = deserializeJson(jsonConfig, payload);
if (error) {
Serial.printf("failed: %s", error.c_str());
return;
} else {
size_t size = serializeJson(jsonConfig, Serial); // printing JSON to Serial for debugging
Serial.printf(", %u bytes\n", size);
// Returns false on initial boot as expected
// Should return true after storing configuration to RTC
if (isConfigUpToDate()) {
Serial.println("Configuration is up-to-date");
publishSensorData();
} else {
storeConfigToRtc();
reboot = true;
mqttClient.disconnect();
// Rebooting ESP32; After reboot subscribe to topic again
// Now, we use the configuration stored in RTC storage
// isConfigUpToDate() should return true
}
}
}
bool isConfigUpToDate() {
// Is this a valid statement to compare a uint64_t with jsonConfig?
return rtcConfig.time > 0 && rtcConfig.time == (uint64_t)jsonConfig["time"];
}
void storeConfigToRtc() {
Serial.println("Store payload to RTC");
rtcConfig.hasConfig = true;
rtcConfig.systemEnabled = jsonConfig["syse"];
rtcConfig.deepSleepEnabled = jsonConfig["dsle"];
rtcConfig.deepSleepInterv = jsonConfig["idsl"];
rtcConfig.httpRequestInterv = jsonConfig["ihttp"];
rtcConfig.time = jsonConfig["time"];
// BLE addresses
JsonArray bleAddresses = jsonConfig["addr"].as<JsonArray>();
for (size_t i = 0; i < MAX_BLE_NUMBER; i++) {
if (i < bleAddresses.size()) {
String addr = bleAddresses[i].as<String>();
strcpy(rtcConfig.bleAddr[i], addr.c_str());
} else {
strcpy(rtcConfig.bleAddr[i], "\0");
}
}
}
void resetRtc() {
Serial.println("Reset RTC data");
rtcConfig.hasConfig = false;
rtcConfig.systemEnabled = false;
rtcConfig.deepSleepEnabled = true;
rtcConfig.deepSleepInterv = 60000000;
rtcConfig.httpRequestInterv = 60000;
rtcConfig.time = 0;
rtcConfig.bleAddr[MAX_BLE_NUMBER][MAC_ADDR_LENGTH] = { 0 };
}
void setup() {
...
if (rtcConfig.wakeupCnt == 0) {
resetRtc();
}
...
topicConfigMac = (char*)malloc(strlen(MQTT_TOPIC_CONFIG) + MAC_ADDR_LENGTH);
strcpy(topicConfigMac, MQTT_TOPIC_CONFIG);
strcat(topicConfigMac, WiFi.macAddress().c_str());
...
}
void loop() {}
因为
rtcConfig.time
最初是0
,所以isConfigUpToDate()
返回false
并将配置存储到RTC中。重新启动后,rtcConfig.time
不再是 0
,应将传感器数据发布到 MQTT 服务器。
从 Mosquitto 的日志文件和分析中,我可以看出该过程陷入了上述方法
isConfigUpToDate()
,该方法将在第一次预期的重新启动后返回false
。但我此时期待true
。
现在,我不知道为什么它会卡在那里。可能有以下几个原因:
是逻辑表达式
rtcConfig.time > 0 && rtcConfig.time == (uint64_t)jsonConfig["time"]
技术上始终有效?
有什么方法可以在不进行USB调试的情况下确认接收到的JSON属性
time
是否按照我的预期设置?
不幸的是,我无法在“生产模式”下通过 USB 端口调试该问题,因为它由电池和太阳能电池板供电。如果我通过 USB 端口调试它,问题永远不会发生,可能是因为我没有足够的耐心等待失败的迭代。它仅在生产模式下 3 或 4 周后发生。有时1周后。很难说。
如有任何想法或意见,我们将不胜感激!我几个月来一直面临这个问题,但无法摆脱它......
提前致谢
编辑
下面是一个有效的 Mosquitto 日志,一切正常:
2024-04-07 04:46:27: New connection from 192.168.178.36:61317 on port 1883.
2024-04-07 04:46:27: New client connected from 192.168.178.36:61317 as esp_dev (p2, c1, k15, u'esp32').
2024-04-07 04:46:27: No will message specified.
2024-04-07 04:46:27: Sending CONNACK to esp_dev (0, 0)
2024-04-07 04:46:27: Received SUBSCRIBE from esp_dev
2024-04-07 04:46:27: esp/config/0C:B8:15:F4:1F:FC (QoS 1)
2024-04-07 04:46:27: esp_dev 1 esp/config/0C:B8:15:F4:1F:FC
2024-04-07 04:46:27: Sending SUBACK to esp_dev
2024-04-07 04:46:27: Sending PUBLISH to esp_dev (d0, q0, r1, m0, 'esp/config/0C:B8:15:F4:1F:FC', ... (108 bytes))
2024-04-07 04:46:27: Received PUBLISH from esp_dev (d0, q1, r0, m2, 'testTopic', ... (86 bytes))
2024-04-07 04:46:27: Sending PUBLISH to paho82806266301 (d0, q0, r0, m0, 'testTopic', ... (86 bytes))
2024-04-07 04:46:27: Sending PUBACK to esp_dev (m2, rc0)
2024-04-07 04:46:27: Received DISCONNECT from esp_dev
2024-04-07 04:46:27: Client esp_dev disconnected.
这是失败的 Mosquitto 日志,它陷入了无限循环。在这里您可以看到 ESP 在收到发布的消息后“主动”与代理断开连接。如果 deserializePayload()
返回
isConfigUpToDate()
,这必须是 false
中的代码。 5-7秒后,它会一遍又一遍地做。2024-04-07 05:31:34: New connection from 192.168.178.36:51254 on port 1883.
2024-04-07 05:31:34: New client connected from 192.168.178.36:51254 as esp_dev (p2, c1, k15, u'esp32').
2024-04-07 05:31:34: No will message specified.
2024-04-07 05:31:34: Sending CONNACK to esp_dev (0, 0)
2024-04-07 05:31:34: Received SUBSCRIBE from esp_dev
2024-04-07 05:31:34: esp/config/0C:B8:15:F4:1F:FC (QoS 1)
2024-04-07 05:31:34: esp_dev 1 esp/config/0C:B8:15:F4:1F:FC
2024-04-07 05:31:34: Sending SUBACK to esp_dev
2024-04-07 05:31:34: Sending PUBLISH to esp_dev (d0, q0, r1, m0, 'esp/config/0C:B8:15:F4:1F:FC', ... (108 bytes))
2024-04-07 05:31:34: Received DISCONNECT from esp_dev
2024-04-07 05:31:34: Client esp_dev disconnected.
2024-04-07 05:31:40: New connection from 192.168.178.36:60107 on port 1883.
2024-04-07 05:31:41: New client connected from 192.168.178.36:60107 as esp_dev (p2, c1, k15, u'esp32').
2024-04-07 05:31:41: No will message specified.
2024-04-07 05:31:41: Sending CONNACK to esp_dev (0, 0)
2024-04-07 05:31:41: Received SUBSCRIBE from esp_dev
2024-04-07 05:31:41: esp/config/0C:B8:15:F4:1F:FC (QoS 1)
2024-04-07 05:31:41: esp_dev 1 esp/config/0C:B8:15:F4:1F:FC
2024-04-07 05:31:41: Sending SUBACK to esp_dev
2024-04-07 05:31:41: Sending PUBLISH to esp_dev (d0, q0, r1, m0, 'esp/config/0C:B8:15:F4:1F:FC', ... (108 bytes))
2024-04-07 05:31:41: Received DISCONNECT from esp_dev
...
infinite loop here until the battery is drained from WiFi connecting
...
mosquitto.conf
...
autosave_interval 1800
autosave_on_changes true
persistence true
persistence_location /var/lib/mosquitto/
...
memset
,因为它损坏了 RTC 内存。
所以我要关闭该线程。感谢@Brits 帮助我,干杯!