Как избежать цикла повторного подключения MQTT

У меня есть следующий код, позволяющий мне управлять своим устройством с моего веб-сайта с помощью mqttbroker, пока доступен Интернет. Я также встроил локальный веб-сервер для управления устройством в случае отключения Интернета, поскольку я все еще подключен к тому же маршрутизатору, к которому подключено мое устройство.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

int ledPin = 2; 

const char* ssid = "SSID";
const char* password = "PASS";
const char* mqtt_server = "MQTTSERVER";
const char* mqtt_user = "MQTTUSER";
const char* mqtt_pass = "MQTTPASS";
const char* mqtt_topic = "topic";
String mqttpayload;

WiFiServer server(80);
WiFiClient espClient; 
PubSubClient client(espClient);

void setup() {
  Serial.begin(115200);  pinMode(ledPin, OUTPUT);  digitalWrite(ledPin, LOW);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) { delay(100); Serial.print(".");  }  Serial.println("");
  
  Serial.print("Connected to WiFi");  
  
  client.setServer(mqtt_server, 1883);    server.begin();  
}

void loop() {
  client.setCallback(callback);
  reconnect();
  if ( mqttpayload == "OFF" ) {   digitalWrite(ledPin, HIGH); Serial.println("Switced OFF"); }
  if ( mqttpayload == "ON" ) {   digitalWrite(ledPin, LOW);  Serial.println("Switced ON"); }
  mqttpayload = "";


  WiFiClient cclient = server.available();
  if (!cclient) {  return;  }  while(!cclient.available()){  }
  String request = cclient.readStringUntil('\r');  Serial.println(request);  cclient.flush();

  int value = HIGH;
  if (request.indexOf("/LED=ON") != -1)   { 
    digitalWrite(ledPin, LOW);    value = LOW;      Serial.println("Publish message: ON");    reconnect();  client.publish(mqtt_topic, "ON", true); 
  } 
  if (request.indexOf("/LED=OFF") != -1)  { 
    digitalWrite(ledPin, HIGH);   value = HIGH;     Serial.println("Publish message: OFF");    reconnect(); client.publish(mqtt_topic, "OFF", true); 
  }

  cclient.println("HTTP/1.1 200 OK");  
  cclient.println("Content-Type: text/html");  
  cclient.println(""); 
  cclient.println("<!DOCTYPE HTML>");  
  cclient.println("<html>");  
  cclient.print("LED status: "); 
  
  if(value == HIGH) {    cclient.print("OFF");  } else {    cclient.print("ON");  }
  cclient.println("<br><br>");  
  cclient.println("Turn <a href=\"/LED=ON\">ON</a><br>");  
  cclient.println("Turn <a href=\"/LED=OFF\">OFF</a><br>");  
  cclient.println("</html>");
  Serial.println("");  
}

void callback(char* topic, byte* payload, unsigned int length) {
  for (int i = 0; i < length; i++) {     mqttpayload += (char)payload[i]; }
}

void reconnect() { 
  if (!client.connected()) { 
    while (!client.connected()) { 
      Serial.print("MQTT..");  
      if (client.connect("2021", mqtt_user, mqtt_pass)) { 
        Serial.println("MQTT connected");        client.subscribe(mqtt_topic);   
      } else { error(); } 
    }  
  }  
  client.loop(); 
}

void error() {  Serial.print("failed, rc=");      Serial.print(client.state());      Serial.println(" try again in 5 seconds");      delay(5000);   }

Проблема заключается в том, что я тестирую его при подключении к маршрутизатору без без Интернета. Код зацикливается, пытаясь подключиться к серверу MQTT, и зависает, что не позволяет мне отправлять локальные HTTP-запросы.

Я попытался изменить цикл повторного подключения MQTT на приведенный ниже, который решает проблему, но создает другую проблему, заключающуюся в задержке HTTP-запросов до 6–9 секунд.

void reconnect() { 
 if (client.connect("2021", mqtt_user, mqtt_pass)) { 
  Serial.println("MQTT connected");
  client.subscribe(mqtt_topic);   
 } else { error(); }
 client.loop(); 
}

Итак, вопрос: что мне делать, чтобы обойти эту проблему?

, 👍1

Обсуждение

Вам следует пытаться подключиться к вашему серверу MQTT только при отсутствии активного соединения. С помощью второго фрагмента кода вы (повторно) подключаете каждую итерацию вашего loop(), и это может привести к задержке, с которой вы, по-видимому, сталкиваетесь. Поместите if (!client.connected) { ... } вокруг кода if (client.connect()) { .. }., @StarCat

@StarCat, если вы посмотрите на основной код, он там есть, и это меня беспокоит. если подключение к Интернету будет потеряно, Arduino не сможет получать мои HTTP-запросы., @ASH

Вы можете ограничить количество попыток повторного подключения, вызывая reconnect() каждые несколько секунд, а не постоянно. У меня были хорошие результаты при проверке каждые 30 секунд. Если вы это сделаете, вам следует вызвать client.loop() из вашего основного loop(), а не из reconnect()., @StarCat

Это довольно просто: на каждой итерации цикла() *если* клиент не подключен, *то* пытайтесь подключиться. Не *пока* клиент не подключен *тогда* попытайтесь подключиться. Каждый раз пробуйте только один раз., @Majenko

Вы можете посмотреть пример PubSubClient mqtt_reconnect_nonblocking, который может быть тем, что вы ищете. Он пытается подключиться только тогда, когда соединения нет (я предполагал, что ваш код уже сделал это, но похоже, что это не так)., @StarCat


1 ответ


0

В цикле сначала проверьте сеть. Вы также можете выполнить проверку связи с Интернетом, чтобы убедиться, что Интернет доступен. Если отрицательный результат, просто пропустите повторное подключение и попробуйте проверить подключение к Интернету или попробуйте другой способ подключения к MQTT или esp.

,