Esp8266 и mqtt

Тема в разделе "ESP8266, ESP32", создана пользователем yden, 23 июн 2018.

  1. yden

    yden Гик

    Добрый всем.
    Подскажите пожалуйста. Есп 8266 в исполнении NodeMcu, с подключенным дисплеем на MAX7219 и датчиком освещенности. Есп разговаривает по mqtt с другими девайсами, в частности сервером УД majordomo. Подписок на топики - 7. Шлет сообщения на 4 топика - настроены таймеры отправки. Так же настроена удаленная прошивка по веб.
    С неясной периодичностью есп теряет связь с mqtt - перестает слать\получать сообщения. Но пинг идет, прошивка "залетает". После перезагрузки модуль начинает работать нормально.
    Ниже прикладываю код (строки управляющие дисплеем выпилил), может что не так закодил:
    Код (C++):
    #include <WiFiUdp.h>
    #include <PubSubClient.h>
    #include <ESP8266WiFi.h>
    #include <ESP8266WebServer.h>
    #include <Adafruit_GFX.h>
    #include <ESP8266mDNS.h>
    // =======================================================================
    // Конфигурация устройства:
    // =======================================================================
    const char* host = "informer_in";
    const char* ssid     = "***";                      // SSID
    const char* password = "***";                    // пароль
    // =======================================================================
    const char *mqtt_server = "192.168.1.70"; // Имя сервера MQTT
    const int mqtt_port = 1883; // Порт для подключения к серверу MQTT
    const char *mqtt_user = "****"; // Логи от сервер
    const char *mqtt_pass = "****"; // Пароль от сервера
    WiFiClient wclient;
    PubSubClient client(wclient);
    int clouds;
    float windSpeed;
    float temp = 0;
    String date;
    String line;
    String currencyRates;
    String scroll_String;
    String text1;
    //датчик света
    const int inRaw = A0; //вход датчик света
    int raw = 0; //сила света
    int raw_mean = 0; //сила света среднее
    int raw_old = 0; //сила света
    String t_out;
    String t_out_delta;
    String t_out_delta_sym;
    String t_banya;
    String t_banya_delta;
    String t_banya_delta_sym;
    String p_atm;
    String p_atm_delta;
    String p_atm_delta_sym;
    boolean mqtt_light_banya = false; //флаг включения света баня
    //подсчет времени
    long previousMillis_time = 0;  // храним время последнего подключения
    long interval_time = 3600000;     //интервал 1 час
    //raw
    long previousMillis_raw = 0;  // храним время последнего подключения
    long interval_raw = 300000;     //интервал
    //mqtt
    long previousMillis_mqtt = 0;  // храним время последнего подключения
    long interval_mqtt = 10000;     //интервал
    //mqtt raw
    long previousMillis_mqtt_raw = 0;  // храним время последнего подключения
    long interval_mqtt_raw = 300000;     //интервал
    //wifi
    long previousMillis_wifi = 0;  // храним время последнего подключения
    long interval_wifi = 10000;     //интервал
    unsigned long currentMillis_wifi = 0;
    // =======================================================================
    // Функция получения данных от сервера
    void callback(char* topic, byte* payload, unsigned int length)
    {
      //--------------------------------------------------------------------------------------
      //температура баня
      if (String(topic) == "ihouse/climat/banya/temp")
      {
        t_banya = "";
        for (int i = 0; i < length; i++)
        {
          t_banya = t_banya +(char)payload[i];
        }
      }
      if (String(topic) == "ihouse/climat/banya/tempDelta")
      {
        t_banya_delta = "";
        for (int i = 0; i < length; i++)
        {
          t_banya_delta = t_banya_delta +(char)payload[i];
        }
      }
      //--------------------------------------------------------------------------------------
      //температура улица
      if (String(topic) == "ihouse/climat/out/temp")
      {
        t_out = "";
        for (int i = 0; i < length; i++)
        {
          t_out = t_out +(char)payload[i];
        }
      }
      if (String(topic) == "ihouse/climat/out/tempDelta")
      {
        t_out_delta = "";
        for (int i = 0; i < length; i++)
        {
          t_out_delta = t_out_delta +(char)payload[i];
        }
      }
      //--------------------------------------------------------------------------------------
      //давление
      if (String(topic) == "ihouse/climat/out/pressAtm")
      {
        p_atm = "";
        for (int i = 0; i < length; i++)
        {
          p_atm = p_atm +(char)payload[i];
        }
      }
      if (String(topic) == "ihouse/climat/out/pressAtmDelta")
      {
        p_atm_delta = "";
        for (int i = 0; i < length; i++)
        {
          p_atm_delta = p_atm_delta +(char)payload[i];
        }
      }
      //--------------------------------------------------------------------------------------
      //свет баня
      if (String(topic) == "ihouse/svet/banya/in")
      {
        if ((char)payload[0] == '1') mqtt_light_banya = true;
        if ((char)payload[0] == '0') mqtt_light_banya = false;
      }
    }
    // =======================================================================
    void reconnect()
    {
      // подключаемся к MQTT серверу
      if (WiFi.status() == WL_CONNECTED)
      {
        if (!client.connected())
        {
          Serial.print("Attempting MQTT connection...");
          if (client.connect("informer_in",mqtt_user, mqtt_pass))
          {
            //подписываемся по топики
            client.subscribe("ihouse/climat/out/temp");
            client.loop();
            client.subscribe("ihouse/climat/out/tempDelta");
            client.loop();
            client.subscribe("ihouse/climat/banya/temp");
            client.loop();
            client.subscribe("ihouse/climat/banya/tempDelta");
            client.loop();
            client.subscribe("ihouse/svet/banya/in");
            client.loop();
            client.subscribe("ihouse/climat/out/pressAtm");
            client.loop();
            client.subscribe("ihouse/climat/out/pressAtmDelta");
            client.loop();
          }
        }  
      }
    }
    // =======================================================================
    void setup_wifi()
    {
        if (currentMillis_wifi - previousMillis_wifi > interval_wifi)
        {
          WiFi.begin(ssid, password); //конектимся
          previousMillis_wifi = currentMillis_wifi;
        }
    }
    // =======================================================================
    void setup()
    {
      // Удаляем предыдущие конфигурации WIFI сети
      WiFi.disconnect(); // обрываем WIFI соединения
      WiFi.softAPdisconnect(); // отключаем отчку доступа(если она была
      WiFi.mode(WIFI_OFF); // отключаем WIFI
      delay(500);
      // присваиваем статичесий IP адрес
      WiFi.mode(WIFI_STA); // режим клиента
      WiFi.config(IPAddress(192, 168, 1, 71), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0), IPAddress(192, 168, 1, 1));
      WiFi.begin(ssid, password);
      delay(10);
      client.setServer(mqtt_server, mqtt_port);
      client.setCallback(callback);
      pinMode(inRaw,  INPUT);
      Serial.begin(115200);                           // Дебаг
    }
    // =======================================================================
    // Функция отправки в mqtt
    void TempSend()
    {
      unsigned long currentMillis_mqtt = millis();
      unsigned long currentMillis_mqtt_raw = millis();
      if (currentMillis_mqtt - previousMillis_mqtt >= interval_mqtt)
      {
        previousMillis_mqtt = currentMillis_mqtt;
        client.publish("ihouse/work/informerIn", String(random(1000)).c_str());
      }
      if (h != h_old)
      {
        client.publish("ihouse/clock/h", String(h).c_str());
        h_old = h;
      }
      if (m != m_old)
      {
        client.publish("ihouse/clock/m", String(m).c_str());
        m_old = m;
      }
      if (currentMillis_mqtt_raw - previousMillis_mqtt_raw >= interval_mqtt_raw)
      {
        previousMillis_mqtt_raw = currentMillis_mqtt_raw;
        client.publish("ihouse/raw", String(raw).c_str()); // отправляем в топик значение освещенности
      }
      delay(10);
    }
    // =======================================================================
    void loop()
    {
      unsigned long currentMillis_time = millis();
      unsigned long currentMillis_raw = millis();
      unsigned long currentMillis_wifi = millis();
      //--------------------------------------------------------------------------------------
      if (WiFi.status() != WL_CONNECTED) //если нет подключения к вифи
      {
        setup_wifi();
      }
      //--------------------------------------------------------------------------------------
      if (!client.connected())
      {
        reconnect();                                        
      }
      //--------------------------------------------------------------------------------------
      raw = analogRead(inRaw);
      //запуск синхронизации времени
      if (currentMillis_time - previousMillis_time >= interval_time)
      {
        previousMillis_time = currentMillis_time;
        getTime();
      }
     
      client.loop();
      TempSend();
    }
     
    благодарю
     
  2. SergeiL

    SergeiL Оракул Модератор

    Не разобрались?
    У меня такого, чтобы совсем отвалилось, не было совсем т.т.т.
    Иногда бывают реконнекты по WiFi и MQTT на ESP, находящихся подальше от точек доступа.

    У Вас только на этой ESP теряется коннект по MQTT?
    Попробуйте добавить счетчик реконнектов по WiFi и MQTT и посмотреть, что вообще происходит на этой ESP.
     
  3. ИгорьК

    ИгорьК Гуру

    Никогда не работал с открытым брокером iot.eclipse.org и не встречался с такой проблемой.

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

    Как решил. Поставил счетчик неуспешных отправок. Если три раза подряд не уходят данные, уничтожаю объект соединения и устанавливаю соединение сначала.

    Вообще, в посылке у меня 7-11 топиков. Считаю не только неуспешные отправки в целом, но и неуспешные отправки в пакете. Их бывает тоже.
    Поскольку следующая отправка зависит от успеха предыдущей, приходится по таймеру, в случае остановки, уничтожать отправку неуспешного пакета.
    Такой вот ооогромный костыль.

    Работает. Уже пять дней без проблем. Раньше в течение суток 2-3 раза отправка останавливалась на 3-4 часа и восстанавливалась сама.
    Повторюсь, проблема только с публичным брокером. Видимо причина на его стороне - забывает о клиенте что ли. Принудительный переконнект - напоминание о себе.

    Код не привожу - он на Lua. Но логикой можно пользоваться. Код в соответствующей теме.
     
    Последнее редактирование: 3 июл 2018
    Mitrandir нравится это.
  4. SergeiL

    SergeiL Оракул Модератор

    А какой у Вас таймаут меду получением, отправкой данных на MQTT сервер, когда теряется связь?
    Может потеря связи происходит из за отсутствия активности долгое время. Я знаю, что в протоколе есть периодический обмен, но, кто его знает...
    У меня максимальный таймаут - 5 минут, на некоторых устройствах чаще, но больше 5 минут нет.
    Устройства или что-то получают, или по таймауту, периодически, шлют свои данные.
    Потери связи - нет.
     
  5. ИгорьК

    ИгорьК Гуру

    Минута. Касается только iot.eclipse.org/
     
  6. SergeiL

    SergeiL Оракул Модератор

    Ну да, тогда проблема не в этом.
    Минута - это не таймаут...