• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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 начинает зависать на этапе подключения.
ОК, Спасибо!
 
Сверху Снизу