ESP32 — спорадический медленный прием сообщений MQTT
Описание проблемы: Каждые ~20+ опубликованных сообщений (с использованием терминала) MCU получает это сообщение с очень заметной задержкой (в основном ~10 секунд, редко до 1 минуты). После получения (печатается в последовательном мониторе) MCU работает должным образом.
Аппаратное обеспечение: ESP32 DEVKIT MCU, PubSubClient.h
для MQTT и WiFi.h
для WiFi.
Важное замечание: код одинаков для ESP8266 и ESP32. Это происходит только на ESP32.
Вопрос. Есть ли у ESP32 известная проблема с получением сообщений MQTT? есть обходной путь? или, возможно, ошибка в коде?
Что я сделал, чтобы попытаться локализовать проблему:
Пробовал на 3 разных ESP32 (2 MCU DEVkit и 1 с реле на плате) - одинаковое поведение - это не конкретная аппаратная проблема MCU.
Использовал другой компьютер для публикации сообщений MQTT (через терминал, MAC и Linux, а также стороннее приложение MQTT) — без изменений. Это не имеет ничего общего с издательской платформой.
Чтобы исключить, что это может быть ошибка брокера MQTT (локальный RPI3, подключенный с помощью кабеля LAN). Подпишитесь на эту тему, чтобы увидеть, повторяется ли задержка. Сервер MQTT получает пабы вовремя. Брокер отвечает вовремя (ожидая получения публикации в Serial Monitor).
добавление мигающего светодиода каждые 200 мс в
loop()
, чтобы убедиться, что MCU не застревает в процессе.loop()
зацикливается, как и ожидалось (см. код ниже).Выделение свободной кучи памяти на последовательный монитор, чтобы увидеть, есть ли какие-либо проблемы с памятью, деградация. Ничего подозрительного.
Упрощение кода: используются сегменты кода из примера 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();
}
}
@Guy . D, 👍0
Обсуждение1 ответ
Если кто-то обнаружит это, столкнувшись с той же проблемой: У меня была похожая проблема на Pico W. Оказалось, что Serial.println() в обратном вызове MQTT затирают стек MQTT+WiFi. Что-то не очень многозадачность. Исправлено отсутствие доступа к последовательному порту Arduino в обратном вызове MQTT.
- esp32-cam публикует изображение в mqtt
- Публиковать данные json в mqtt
- Не удалось подключиться к брокеру MQTT через esp8266/32 и pub/sub client
- PubSubClient: Подписка работает, но обратный вызов никогда не вызывался
- Подключение ESP32 через MQTT
- Невозможно подключить ESP32 к Mosquitto на Raspberry с использованием сертификатов
- Проблема с подключением MQTT PubSubClient к ESP32
- Несколько тем MQTT
Код, который вы разместили, не компилируется, так как нет
loop_buttons()
., @StarCat@StarCat Ты прав. Это остатки. Пожалуйста, прокомментируйте это., @Guy . D
чувак, помог ответ?, @Juraj
У меня очень похожая проблема, но я использую ESP8266 (наблюдайте за этим на разных типах - NodeMCU, ESP-01S и т. д.). Я очистил обратный вызов MQTT - Serial там не используется (пытался следовать тому, что было предложено Accomation ниже) - безуспешно., @Aleksey Linetskiy