Помогите найти, где задержка происходит!
- Войдите на сайт для отправки комментариев
Уважаемые сторожилы! Подскажите, пожалуйста, как избавиться от пятисекундной задержки?
Ситуация: у меня esp8266, коннектится по вайфаю, передает данные по протоколу MQTT. Все успешно. Пока работает сервер MQTT.
Как только сервер отключаешь - ESP8266 начинает тупить. Задержка составляет ровно 5 секунд на 1 проход. Исходя из чего я могу сделать вывод, что оно где-то установлено программно. Но где - найти не могу, облазил библиотеки на предмет delay - там ничего такого нет!
В следующем сообщении прикладываю код скетча и код библиотеки. Если еще что-то нужно - напишите, выложу.
Экспериментировал:
Как только из loop убираешь вот этот if - все работает шустро:
if (client.connect(MQTT::Connect("arduinoClient")
.set_auth("testeruser", "testpass")))
Код скетча: /* Basic MQTT example with Authentication - connects to an MQTT server, providing username and password - publishes "hello world" to the topic "outTopic" - subscribes to the topic "inTopic" */ #include <ESP8266WiFi.h> #include <PubSubClient.h> const char *ssid = "ssid"; // cannot be longer than 32 characters! const char *pass = "passw"; // // Update these with values suitable for your network. IPAddress server(172, 168, 1, 77); void callback(const MQTT::Publish& pub) { // handle message arrived } WiFiClient wclient; PubSubClient client(wclient, server); void setup() { // Setup console Serial.begin(115200); delay(10); Serial.println(); Serial.println(); } void loop() { Serial.println("HELLO!"); if (WiFi.status() != WL_CONNECTED) { Serial.print("Connecting to "); Serial.print(ssid); Serial.println("..."); WiFi.begin(ssid, pass); if (WiFi.waitForConnectResult() != WL_CONNECTED) return; Serial.println("WiFi connected"); } if (WiFi.status() == WL_CONNECTED) { if (!client.connected()) { // Serial.println("Connecting to MQTT server"); if (client.connect(MQTT::Connect("arduinoClient") .set_auth("testeruser", "testpass"))) { // Serial.println("Connected to MQTT server"); //client.set_callback(callback); //client.publish("outTopic","hello world"); //client.subscribe("inTopic"); } // else { // Serial.println("Could not connect to MQTT server"); // } } if (client.connected()) client.loop(); } }Не то ищете, такое на delay() никогда не делается. Это коннект-таймаут, отрабатывается например в строчке 245 кода в сообщении #3. само значение, судя по всем, задано в файле MQTT.h или где-то еще выше.
Можете попробовать убавить таймаут, например до 2х или даже 1 секунды. Но совсем обнулять таймаут нельзя, иначе у вас и при подключении сервера MQTT перестанет работать.
спасибо, поищу. Меня в принципе не напрягает то, что коннект ждет 5 секунд и отваливается по таймауту.
Меня напрягает, что в эти 5 секунд подвешивается программа.
Я думал где-то delay, и надо его переписать через millis().
А с таймаутами так нельзя,да?
Я думал где-то delay, и надо его переписать через millis().
А с таймаутами так нельзя,да?
похоже вы строчку, которую я указал - даже не смотрели. Она уже через миллис
смотрел, и видел что библиотека вся в целом через миллис написана. Поэтому и удивило: почему цикл loop зависает на 5 секунд, если там через миллис, и вроде как остальная часть программы должна выполняться дальше, если та часть, которая ждет коннекта к МQTT брокеру, входит в режим ожидания...
Посмотрел значение параметра
MQTT_KEEPALIVE, оно равно 15 секунд
Это из MQTT.cpp
// Connect class Connect::Connect(String cid) : Message(CONNECT), _clean_session(true), _clientid(cid), _will_message(nullptr), _will_message_len(0), _keepalive(MQTT_KEEPALIVE) {}для эксперимента поменял MQTT_KEEPALIVE на 1 секунду - не помогло: задержка все равно 5 секунд идет, если нет коннекта. Ищу в том же направлении.
тогда такой вопрос:
что происходит внутри данной строки вызова условия?
if (client.connect(MQTT::Connect("NNN").set_auth(MQTT_USER, MQTT_PASS)))
На сколько я понял,
- Вызывается функция MQTT.connect с параметром имени сервера (NNN).
- далее вызывается функция client.connect с параметром, который возвратила предыдущая функция - точка - set_auth (логин, пароль).
Получается, в итоге в условии будет либо true если законнектились, либо false, если не законнектились.
Вопросы:
1) Что возвращает первая функция MQTT.connect
2) Как проверить, какая из двух используемых тут функций вызывает задержку в 5 секунд?
методом поочередного комментирования кусков кода вычислил, что тупит 207я строка из файла pubsubclient.cpp
Вот эта:
result = _client.connect(server_hostname.c_str(), server_port);
Если кто что толковое подскажет - буду благодарен. Что делает эта строчка? Куда смотреть? Что искать?
Целый день сижу втыкаю (((
Продолжаю поиски проблемы.
Пока решил вопрос отсрочкой на реконнект в 60 секунд в случае неудачного коннекта. Криво, конечно, но по другому не понимаю как.
Кривость в том, что в случае неработающего сервера MQTT выполнение команд все равно будет подвисать 1 раз в минуту на 5 секунд.
Может, кто что порекомендует более адекватное...
#include <ESP8266WiFi.h> #include <PubSubClient.h> /************************* WiFi Access Point *********************************/ #define WLAN_SSID "MGTS_GPON_929E" #define WLAN_PASS "SPL4MTQ6" /************************* Mosquitto Setup *********************************/ #define MOSQUITTO_SERVER "192.168.1.71" #define MOSQUITTO_PORT 1883 // use 8883 for SSL #define MQTT_USER "kstud" #define MQTT_PASS "belijsneg5333" #define CLIENTNAMEUNIQUE "NIKArdnr02" /************************* Device Setup *********************************/ #define KORIDOR1SVETPIN 5 //5=d1 nodemcu v3 #define KNOPKA1PIN 4 //4=d2 nodemcu v3 #define KNOPKA2PIN 13 //13=d7 nodemcu v3 #define KNOPKA3PIN 12 //12=d6 nodemcu v3 #define KNOPKA4PIN 14 //14=d5 nodemcu v3 /************************* Topics Setup *********************************/ #define KORIDOR1SVETTOPIC "/home/koridor1/svet" WiFiClient wclient; PubSubClient client(wclient, MOSQUITTO_SERVER, MOSQUITTO_PORT); unsigned long t=0; //для кнопки1 вспомогательная переменная bool ignoreonevalue=0; // когда сработал выключатель, то игнорируем одну следующую команду, пришедшую из топика. bool svetstate=0; bool delayflag = 0; unsigned long tt2=0; // Функция получения данных от сервера void callback(const MQTT::Publish& pub) { Serial.print(pub.topic()); // выводим в сериал порт название топика Serial.print(" => "); Serial.println(pub.payload_string()); // выводим в сериал порт значение полученных данных String payload = pub.payload_string(); // считываем значение, пришедшее по топику // обработка включения люстры if(String(pub.topic()) == KORIDOR1SVETTOPIC) // проверяем из нужного ли нам топика пришли данные { if (ignoreonevalue==0) // если управление пришло извне, а не от выключателя на том же устройстве NodeMCU, где и люстра располагается { svetstate = payload.toInt(); // преобразуем полученные данные digitalWrite(KORIDOR1SVETPIN,svetstate); // включаем светодиод } else ignoreonevalue=0; // если сигнал пришел от выключателя, находящегося на том же устройстве NodeMCU, что и люстра } } void setup() { // подключаемся к wi-fi if (WiFi.status() != WL_CONNECTED) { Serial.print("Connecting to "); Serial.print(WLAN_SSID); Serial.println("..."); WiFi.begin(WLAN_SSID, WLAN_PASS); if (WiFi.waitForConnectResult() != WL_CONNECTED) return; Serial.println("WiFi connected"); } //sensors.begin(); Serial.begin(115200); delay(10); Serial.println(); Serial.println(); pinMode(KORIDOR1SVETPIN, OUTPUT); pinMode(KNOPKA1PIN,INPUT); pinMode(KNOPKA2PIN,INPUT); pinMode(KNOPKA3PIN,INPUT); pinMode(KNOPKA4PIN,INPUT); } void loop() { // обработка нажатия кнопки. +это событие идет в опенхаб. включаем-выключаем свет, подключенный к этому же NodeMCU, что и выключатель if (t+500UL<millis()) //задержка полсекунды при нажатии кнопки, чтобы она не срабатывала 10 раз подряд { if (digitalRead(KNOPKA1PIN)==1 or digitalRead(KNOPKA2PIN)==1 or digitalRead(KNOPKA3PIN)==1 or digitalRead(KNOPKA4PIN)==1) //если нажата одна их 4х проходных кнопок { t=millis(); svetstate=!svetstate; // меняем значение светодиода на противоположное Serial.println (svetstate); digitalWrite(KORIDOR1SVETPIN,svetstate); if (WiFi.status() == WL_CONNECTED and client.connected()) { client.publish(KORIDOR1SVETTOPIC,String(svetstate)); // отправляем в топик для термодатчика значение температуры ignoreonevalue=1; //защита от повторного переключения состояния люстры, когда команда в топике вернется от сервера } } } if (tt2+60000UL<millis()) delayflag=0; // подключаемся к MQTT серверу if (WiFi.status() == WL_CONNECTED) { if (!client.connected() and delayflag==0) { Serial.println("Connecting to MQTT server"); if(client.connect(MQTT::Connect(CLIENTNAMEUNIQUE).set_auth(MQTT_USER, MQTT_PASS))) { Serial.println("Connected to MQTT server"); client.set_callback(callback); client.subscribe(KORIDOR1SVETTOPIC); // подписываемся по топик с данными для светодиода } else { delayflag=1; tt2=millis(); Serial.println("Could not connect to MQTT server"); } } if (client.connected()) { client.loop(); } } // конец основного цикла }А пингануть сервер? Если отвечает то только тогда конектится?
пингануть? в принципе вариант. Где можно посмотреть, какими командами получить результат пинга (успех-неудача)?
https://github.com/dancol90/ESP8266Ping первая ссылка гугля. Забанили?
помню-помню, в среде разработчиков принято общаться саркастически...
PS Благодарю за ссылку.
А пингануть сервер? Если отвечает то только тогда конектится?
Проверил я предложенный Вами вариант. Пинг работает!
НО: он работает точно также, как и приведенный мной код: в момент пинга, то есть вот на этой строке:
выполнение цикла loop на esp8266 подвешивается ровно на те же 5 секунд! Забавно получается ))
В библиотеке пинга есть функция установки таймаута. Правда там как мне показалась минимум секунда. Так что меньше похоже не получится. Но это нормальное поведение в условиях сетевого коннекта. Тут или шашечки или ехать.
да, увидел единичку и неуверенный комментарий, что возможно, это секунды. В то же время в библиотеке стоит 1, а задержка 5 секунд.
На данный момент я остановился на следующем решении:
- если коннект к MQTT серверу произошел, то и так все в порядке в рамках имеющейся библиотеки pubsubclient.
- если коннекта нет, то начинаем отсчет. В течение 10 минут даже не пробуем коннектиться. Выполняем себе код, предназначенный для офлайн режима работы esp8266. Через 10 минут пробуем коннект еще раз.
Таким образом, получается глюк с подвисанием программы всего 5 секунд 1 раз в 10 минут. Это практически идеально.
Всех еще раз благодарю за участие. Тему закрываю.