ESP32 — спорадический медленный прием сообщений MQTT

Описание проблемы: Каждые ~20+ опубликованных сообщений (с использованием терминала) MCU получает это сообщение с очень заметной задержкой (в основном ~10 секунд, редко до 1 минуты). После получения (печатается в последовательном мониторе) MCU работает должным образом.

Аппаратное обеспечение: ESP32 DEVKIT MCU, PubSubClient.h для MQTT и WiFi.h для WiFi.

Важное замечание: код одинаков для ESP8266 и ESP32. Это происходит только на ESP32.

Вопрос. Есть ли у ESP32 известная проблема с получением сообщений MQTT? есть обходной путь? или, возможно, ошибка в коде?

Что я сделал, чтобы попытаться локализовать проблему:

  1. Пробовал на 3 разных ESP32 (2 MCU DEVkit и 1 с реле на плате) - одинаковое поведение - это не конкретная аппаратная проблема MCU.

  2. Использовал другой компьютер для публикации сообщений MQTT (через терминал, MAC и Linux, а также стороннее приложение MQTT) — без изменений. Это не имеет ничего общего с издательской платформой.

  3. Чтобы исключить, что это может быть ошибка брокера MQTT (локальный RPI3, подключенный с помощью кабеля LAN). Подпишитесь на эту тему, чтобы увидеть, повторяется ли задержка. Сервер MQTT получает пабы вовремя. Брокер отвечает вовремя (ожидая получения публикации в Serial Monitor).

  4. добавление мигающего светодиода каждые 200 мс в loop(), чтобы убедиться, что MCU не застревает в процессе. loop() зацикливается, как и ожидалось (см. код ниже).

  5. Выделение свободной кучи памяти на последовательный монитор, чтобы увидеть, есть ли какие-либо проблемы с памятью, деградация. Ничего подозрительного.

  6. Упрощение кода: используются сегменты кода из примера ESP32 Wi-Fi и MQTT pubsub, при этом отключаются все функции исходного кода (с и без). Задержка по-прежнему случается время от времени.

OUTPUT1 – отправка "0" и "1" почти одновременно, задержка почти 15 секунд

13:31:21.516 -> Message arrived [myHome/test] 0 <--- right after this, "1" was sent
13:31:22.510 -> 278616 <---- free heap size (send every 1000 ms. non-blocking)
13:31:23.570 -> 278616
13:31:24.630 -> 278616
13:31:25.657 -> 278616
13:31:26.718 -> 278616
13:31:27.778 -> 278616
13:31:28.805 -> 278616
13:31:29.866 -> 278616
13:31:30.926 -> 278616
13:31:31.954 -> 278616
13:31:33.014 -> 278616
13:31:34.075 -> 278616
13:31:35.102 -> 278616
13:31:35.964 -> Message arrived [myHome/test] 1 <--- received 15 sec later

ВЫВОД-2: Код

#include <WiFi.h>
#include <PubSubClient.h>

WiFiClient espClient;
PubSubClient client(espClient);


const char *mqtt_server = "192.168.2.100";


void setup_wifi()
{

        delay(10);
        // Начнем с подключения к сети WiFi
        Serial.println();
        Serial.print("Connecting to ");
        // Serial.println(ssid);

        WiFi.mode(WIFI_STA);
        WiFi.begin("iot", "GdS");

        while (WiFi.status() != WL_CONNECTED)
        {
                delay(500);
                Serial.print(".");
        }

        Serial.println("");
        Serial.println("WiFi connected");
        Serial.println("IP address: ");
        Serial.println(WiFi.localIP());
}

void callback(char *topic, byte *payload, unsigned int length)
{
        Serial.print("Message arrived [");
        Serial.print(topic);
        Serial.print("] ");
        for (int i = 0; i < length; i++)
        {
                Serial.print((char)payload[i]);
        }
        Serial.println();

        // Включаем светодиод, если в качестве первого символа была получена 1
}

void reconnect()
{
        // Цикл, пока мы снова не подключимся
        while (!client.connected())
        {
                Serial.print("Attempting MQTT connection...");
                // Создаем случайный идентификатор клиента
                String clientId = "ESP8266Client-";
                clientId += String(random(0xffff), HEX);
                // Попытка подключения
                if (client.connect(clientId.c_str()),"guy","kupelu9e")
                {
                        Serial.println("connected");
                        // После подключения публикуем объявление...
                        client.publish("myHome/log", "hello world");
                        // ... и переподписаться
                        client.subscribe("myHome/test");
                }
                else
                {
                        Serial.print("failed, rc=");
                        Serial.print(client.state());
                        Serial.println(" try again in 5 seconds");
                        // Подождите 5 секунд перед повторной попыткой
                        delay(5000);
                }
        }
}

void setup()
{
        Serial.begin(115200);
        setup_wifi();
        client.setServer(mqtt_server, 1883);
        client.setCallback(callback);
        reconnect();
}
void loop()
{
        loop_buttons();
        if (!client.connected())
        {
                reconnect();
        }
        client.loop();
        static unsigned long lastentry = 0;
        static unsigned long lastentry2 = 0;
        if (millis() - lastentry > 200)
        {
                pinMode(2, OUTPUT);
                digitalWrite(2, !digitalRead(2));
                lastentry = millis();
        }
        delay(50);
        if (millis() - lastentry2 > 1000)
        {
                Serial.println(ESP.getFreeHeap());
                lastentry2 = millis();
        }
}

, 👍0

Обсуждение

Код, который вы разместили, не компилируется, так как нет loop_buttons()., @StarCat

@StarCat Ты прав. Это остатки. Пожалуйста, прокомментируйте это., @Guy . D

чувак, помог ответ?, @Juraj

У меня очень похожая проблема, но я использую ESP8266 (наблюдайте за этим на разных типах - NodeMCU, ESP-01S и т. д.). Я очистил обратный вызов MQTT - Serial там не используется (пытался следовать тому, что было предложено Accomation ниже) - безуспешно., @Aleksey Linetskiy


1 ответ


1

Если кто-то обнаружит это, столкнувшись с той же проблемой: У меня была похожая проблема на Pico W. Оказалось, что Serial.println() в обратном вызове MQTT затирают стек MQTT+WiFi. Что-то не очень многозадачность. Исправлено отсутствие доступа к последовательному порту Arduino в обратном вызове MQTT.

,