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?
loop()
and this might introduce the delay you seem to be experiencing. Place anif (!client.connected) { ... }
around theif (client.connect()) { .. }
code.reconnect()
every few seconds and not continuously. I've had good results with checking once every 30 seconds. If you do that, you should callclient.loop()
from your mainloop()
and not fromreconnect()
.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).