ESP32、ArduinoJSON 和 MQTT:卡在流程链中

问题描述 投票:0回答:1

我的应用程序有一段时间遇到了一些麻烦,无法弄清楚为什么 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/
...


c++ json mqtt esp32 arduinojson
1个回答
0
投票
memset

,因为它损坏了 RTC 内存。

所以我要关闭该线程。感谢@Brits 帮助我,干杯!

© www.soinside.com 2019 - 2024. All rights reserved.