1

I have the following code designed to allow me to control my device from my website using mqtt broker while internet is available. I also built in a local webserver to control the device in case of internet outage given I'm still connected to the same router my device is connected to.

#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);   }

The problem lies when I test it while connected to my router with no internet. The code loops trying to connect to MQTT server and get stuck which doesn't allow me to send local HTTP requests.

I tried modifying the MQTT reconnect loop to the one below, which solves the problem but introduces another issue which is delaying the HTTP requests up to 6-9 seconds.

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

So the question here, what should I do to get around this issue?

5
  • You should only try connecting to your MQTT server when there's no active connection. With your second piece of code you are (re)connecting every iteration of your loop() and this might introduce the delay you seem to be experiencing. Place an if (!client.connected) { ... } around the if (client.connect()) { .. } code.
    – StarCat
    Commented Feb 15, 2021 at 10:48
  • @StarCat if you look at the main code, it's there, and this is what makes it troublesome to me. if internet connectivity is lost, this will hold Arduino from receiving my HTTP requests.
    – ASH
    Commented Feb 15, 2021 at 10:54
  • You could throttle the amount of reconnect attempts by only calling reconnect() every few seconds and not continuously. I've had good results with checking once every 30 seconds. If you do that, you should call client.loop() from your main loop() and not from reconnect().
    – StarCat
    Commented Feb 15, 2021 at 11:05
  • It's quite simple: on each iteration of loop() if the client isn't connected then try to connect. Not while the client isn't connected then try to connect. Only try once each time through.
    – Majenko
    Commented Feb 15, 2021 at 16:39
  • You could look at the PubSubClient example mqtt_reconnect_nonblocking which might be what you're looking for. It only tries to connect when there's no connection (I assumed your code already did this, but it looks like it doesn't).
    – StarCat
    Commented Feb 15, 2021 at 18:54

1 Answer 1

0

In the loop, check the network first, you can also ping to internet to make sure the internet is available. If negative, just skip reconnecting and try to check the internet connection or try another way to connect to MQTT or esp.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.