• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Проверка наличия соединения с MQTT брокером

Tartuffe

New member
Добрый день!

Для подключения к брокеру использую такой код:

Код:
void loop() {
  // подключаемся к wi-fi
  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");
  }
  // подключаемся к MQTT серверу
  if (WiFi.status() == WL_CONNECTED) {
      if (!client.connected())
      {
          Serial.println("Connecting to MQTT server");
          if (client.connect(MQTT::Connect("arduinoClient2").set_auth(mqtt_user, mqtt_pass)))
            {
            Serial.println("Connected to MQTT server");
            client.set_callback(callback);
            client.subscribe("test/led"); // подписывааемся на топик с данными для светодиода
            client.subscribe("test/t"); // подписывааемся на топик с данными для предельной температуры
            }
         else
            {
        Serial.println("Could not connect to MQTT server"); 
            }
      }
      if (client.connected())
        {
        client.loop();
        TempSend(); // читаем и отправляем данные с датчика температуры
       // дальше, не интересно...
   }
При такой организации проверки подключения к брокеру (НЕ Wi-Fi), эта самая проверка осуществляется только при включении (перезагрузке) ESP. Если же ESP однажды зацепилась (client.connected()) и тупо выдернуть шнурок (не электрический, разумеется) из Wi-Fi роутера, то статус client.connected() не изменится, в то время как связи с брокером не будет. Что мне вообще непонятно, так это то, что в этом случае и if (client.connected()) также не выполняется и считывание температуры также не происходит...
Если воткнуть шнурок обратно, то происходит повторное соединение с брокером и все продолжает работать, как и должно.
Отсюда вопрос: как намастырить проверку соединения с брокером, чтобы при потере связи, можно было бы, скажем, что-то включить/выключить и проч.?
 

Tartuffe

New member
На сколько я понял, затык наступает на строке: client.loop(); То есть void loop() на этом застревает и продолжается только тогда, когда либо появляется связь с брокером, либо сначала пропадает, а потом появляется Wi-Fi. Тогда уже все идет понятно: попытка подключиться к Wi-Fi, потом к брокеру...
 

Mоnk

Member
Проверять (пинговать) хотя бы раз в час какой-либо сервер в интернет, хотя бы тот же m21.cloudmqtt.com. Но недавно наткнулся на отказ пинговаться m13.cloudmqtt.com, хотя как брокер тот работал прекрасно. Так что пингую Гугль.ру, который уже пару раз менял свой ip.
#include <ESP8266Ping.h> //---------- GitHub - dancol90/ESP8266Ping: Ping library for ESP8266 Arduino core
...и если пинг есть, можно коннектица к брокеру и слать данные.
Код:
void Sub_Pub()  // === subscribe & publish
{
  lcd.setCursor(23, 0);
  (WiFi.status() == WL_CONNECTED ? (lcd.write(244)) : (lcd.write(16)));
  if (GnP == 0) // ============ Если пинг удачный
  {
// ========================================================
    if (!client.connected())
    {
      bool success;
      if (strlen(mqttuser) > 0) // if (mqttuser.length() > 0)
      {
        success = client.connect( MQTT::Connect( deviceId ).set_auth(mqttuser, mqttpass) );
      }
      else
      {
        success = client.connect( deviceId );
      }
      if (success)
      {
        pubConfig();
        client.set_callback(onMessageArrived);
        client.subscribe(prefix);                 // for receiving HELLO messages
        client.subscribe(prefdev + "/+/control"); // for receiving GPIO control messages for ALL widgets
      }
      else
      {
        write_on_LCD(23, 0, 253);
      }
    }
// ========================================================
    if (client.connected())
    {
      if (needPubConfig)
      {
        pubConfig();
      }

      yield();

      if (needControlGPIO)
      {
        controlGPIO();
      }

// ========================== publish =========================================================

      if( count10 < 10)
      {
        count10 ++;
      }
      else
      {
        pubStatus(sTopic[0], "{\"status\":\"" + WiFi.SSID() + " " + WiFi.RSSI() + "dbm " + addZero(dayOfMonth, 2, " ") + "." + addZero(monthDS, 2, "0") + ".20" + addZero(yearDS, 2, "0") + " " + addZero(hourDS, 2, "0") + ":" + addZero(minuteDS, 2, "0") + ":" + addZero(secondDS, 2, "0") + RTC_S + " " + ESP.getFreeHeap() + "\"}"); // Дата и Время
        pubStatus(sTopic[1], "{\"status\":\"" + Weather_tS + " °C ▫ " + Weather_hS + " %\"}");
        pubStatus(sTopic[8], "{\"status\":\"" + DS18B20_tS + " °C\"}");
        pubStatus(sTopic[9], "{\"status\":\"" + String(analogRead(A0) * 0.09765625)+ " %\"}");
        count10 = 0;
      }
      client.loop();
    }
  }
  else
  {
    write_on_LCD(23, 0, 253);
  }
}
Сразу вопрос, почему у Вас сначала client.loop();, а потом публикация данных?
 

Tartuffe

New member
Проверять (пинговать) хотя бы раз в час какой-либо сервер в интернет...
Да, идея хорошая... Но в какую часть кода вставить эту проверку? Ведь при потере связи ни одна из строк в void loop() не выполняется...

Сразу вопрос, почему у Вас сначала client.loop();, а потом публикация данных?
Наверное потому, что я бездумно содрал у кого-то этот код... ))) В самом деле, если бы Вы или кто-нибудь хоть вкратце пояснили, что это за client.loop(); и общий принцип работы этой библиотеки, может я и не задавал бы глупых вопросов... (с библиотеками у меня что-то вообще не складывается).
Кстати, я перемещал client.loop(); в конец кода - результат тот же (бессмысленно тыкать в разные части кода, не понимая что делаешь)...
 
Последнее редактирование:

Mоnk

Member
Сам я не достаточно грамотен, поэтому "бездумно сдираю". Где-то натыкался, что этот самый клиент.луп() не только правильно выстраивает структуру данных для брокера, но еще и пингует брокер.
Но в какую часть кода вставить эту проверку?
Код:
void loop()
{
  newPos = myEnc.read()/12;
  if (pos != newPos) encoderPosition();

  button1.tick();

  timeNow = millis();
  if ((timeNow - timer1s) > 1000) //---------- 1 секунда
  {
    timer1s = timeNow;
      getDateDS3231();
      showTime();
      EEPROM_auto_save();
      getDS18B20(id_DS18B20);
      Sub_Pub();  //---- subscribe & publish

    timer10s ++; //---------- 10 секунд
      if (timer10s == 10)
      {
        getWeather();
        heat_ON_OFF();
        light_ON_OFF();
        timer10s = 0;
      }

    timer600s ++; //---------- 600 секунд
      if (timer600s == 600)
      {
        WiFidog();
        timer600s = 0;
      }
  }

  server.handleClient();
  yield();
}
Sub_Pub(); я уже показывал.
 

JI_John

Member
Ваш код зависает при попытке подключения к брокеру в каждом цикле.
Разбейте вашу функцию void loop() на части и проверяйте подключение не в каждом цикле,
а периодически.
Код:
void loop()
    {
     client.loop();
     MQTT();
     temp_ds18b20();
     led();

    if (millis() - last_mls > 60000)     //проверка подключений раз в 60 сек
       {
       last_mls = millis();
       reconnect_server();
          }
    }
//-------------------------------------------------------------------------------          
void MQTT()
         {  
        //публикуем топики
        }
//--------------------------------------------------------------------------------  
void temp_ds18b20()
        {
       //Чтение текущих значений датчика
       }
//--------------------------------------------------------------------------------  
void led()
       {
       // Что-то делаем со светодиодом
       }
//---------------------------------------------------------------------------------      
void reconnect_server()
        {
       //функция проверки подключения
        }
 

Tartuffe

New member
Ваш код зависает при попытке подключения к брокеру в каждом цикле.
Что Вы подразумеваете под попыткой подключения в каждом цикле? Эта строка (client.connect(MQTT::Connect("arduinoClient2").set_auth(mqtt_user, mqtt_pass))) является подключением?
При первом проходе, наверное, да. При этом выражение client.connected() получает значение 1 (True) и во втором "проходе" в if (!client.connected()) мы уже не попадаем (то есть не подключаемся заново), а идем в if (client.connected()), где собственно читаем данные с датчика и проч. При потере связи с брокером, client.connected() должен изменить свое значение на 0 (false), но, на сколько я понимаю, этого не происходит... Где идет отсыл на проверку состояния соединения, в client.loop(); или где???
 

JI_John

Member
Не забывайте, это ARDUINO IDE, а не плоноценный компилятор.
Тут нужно искать не почему не работает, а как заставить работать.
Упрощайте код, разделяйте задачи, не вставляйте все в одну функцию.
У вас - если не подключено - подключаем.
если подключено - выполняем код.
Зачем так? Зачем второй if?
Если не подключено - подключаем, иначе считается подключенным, выполняем код.
 

Tartuffe

New member
JI_John, если честно, трудно привыкнуть, что что-то работает неправильно или вообще не работает не потому, что я что-то делаю не так, а просто - не работает...)))

Зачем If'ы нужны мне понятно. Я не понимаю, в каком месте идет проверка наличия соединения! Это не client.connected() (потому что при потере связи значение не меняется), это и не client.loop() (потому что библиотека PubSubClient.h должна возвращать или false или true при потере связи, но этого то ли не происходит, то ли я что-то не понимаю)... А что тогда?

P.S. Судя по тому, сколько вопросов вызывает у начинающих эта библиотека, ее пользуют очень многие... Почему ж тогда никто не парится, как будет себя вести девайс без связи? Особенно если ты находишься от него бог знает на каком расстоянии, а бесконтрольный девайс этот может дров наломать...
 

JI_John

Member
Почему ж тогда никто не парится, как будет себя вести девайс без связи?
Может потому что это не Arduino Uno и он не расчитан на работу без связи.
Этот чип скорее игрушка для обучения а не "военный" прибор.
За 1$ денег требовать от него стабильной и безглючной работы как-то наивно.
В локальной сети, для несложных задач, более мение стабильно работает.
Это просто мое мнение...
 

Tartuffe

New member
JI_John, в данном конкретном случае к чипу как раз никаких претензий нет. У меня вопрос чисто программный. Впрочем, если чип стоит 1$ (хоть что-то), то софт к нему и вовсе бесплатный... Если дешево хорошо не бывает, то что говорить про "бесплатно"?
Просто хочется поиграть "на старости лет"... В моем детстве, например, каких-нибудь радиоуправляемых машинок не было даже в самых смелых фантазиях, а тут на копеечном чипе можно столько интересных штуковин смастырить... )))
 

JI_John

Member
Ну так и в моем детстве игрушки деревянными были. Это сейчас появилось время
что-то собрать, поиграться. Чипы, да, копеечные. Софт - бесплатный. Ну так он
и работает как бесплатный.
Валялась старая материнка от нэтбука, поставил жесткий на 80 гиг,
установил Windows XP, majordomo, mosquitto (брокер). Привязал к локальной сети.
К интернету не привязывал, нет надобности. Засунул в кладовку (чтоб не мешалось)
Вобщем с этим железом и играюсь. Все управление идет через брокер. Потери связи не
наблюдалось (релюшки клацают, датчики работают). Есть и недостатки. Один модуль может
публиковать не более 5 топиков, если больше - зависает в момент подключения.
Почему? Ответа не нашел, многие на это жалуются. Majordomo пингует все модули и ведет логи.
В случае аварии сообщает. Пока, месяца 3, работает нормально.
 

kab

New member
Ну так и в моем детстве игрушки деревянными были. Это сейчас появилось время
что-то собрать, поиграться. Чипы, да, копеечные. Софт - бесплатный. Ну так он
и работает как бесплатный.
Валялась старая материнка от нэтбука, поставил жесткий на 80 гиг,
установил Windows XP, majordomo, mosquitto (брокер). Привязал к локальной сети.
К интернету не привязывал, нет надобности. Засунул в кладовку (чтоб не мешалось)
Вобщем с этим железом и играюсь. Все управление идет через брокер. Потери связи не
наблюдалось (релюшки клацают, датчики работают). Есть и недостатки. Один модуль может
публиковать не более 5 топиков, если больше - зависает в момент подключения.
Почему? Ответа не нашел, многие на это жалуются. Majordomo пингует все модули и ведет логи.
В случае аварии сообщает. Пока, месяца 3, работает нормально.
Я вот в эту тему еще не вникал:
- А можно в двух словах пояснить, что такое "модуль", "топик" и "публиковать" в этом контексте?
 

JI_John

Member
Модуль - имелась в виду ESPшка. И MQTT брокер, подписка и публикация сообщений в нем.
 

Tartuffe

New member
JI_John, кстати, а как Вы используете mosquitto, если он позволяет бесплатно только 10 топиков публиковать? На разные e-mail'ы регистрировали или платите?
 

kab

New member
Модуль - имелась в виду ESPшка. И MQTT брокер, подписка и публикация сообщений в нем.
цитата
Один модуль может
публиковать не более 5 топиков
означает, что к одному ESP можно подключить не более 5 датчиков?
 

JI_John

Member
он позволяет бесплатно только 10 топиков
Я писал - mosquitto у меня запущен на локальном сервере.

означает, что к одному ESP можно подключить не более 5 датчиков?
Это обозначает что если на одой ESP висит несколько датчиков и реле, и он отправляет их состояние в MQTT брокер, то 5 (или 6 точно не помню) отправляются стабильно. При попытке добавить еще хоть одно значение ESP начинает зависать на этапе подключения.
 
  • Like
Реакции: kab

kab

New member
Я писал - mosquitto у меня запущен на локальном сервере.


Это обозначает что если на одой ESP висит несколько датчиков и реле, и он отправляет их состояние в MQTT брокер, то 5 (или 6 точно не помню) отправляются стабильно. При попытке добавить еще хоть одно значение ESP начинает зависать на этапе подключения.
ОК, Спасибо!
 
Сверху Снизу