I’ve had mixed issues with trying to manage my wifi, cloud and mqtt connections manually. I’m hoping someone can share some thoughts or provide some advice. This code works fine under normal circumstances, but when the network gives out or I reboot the modem I often have to go to all my devices and force a reset. Managing the connection to handle outages has been frustrating so far.
The requirements I have for my device are that a connection to the local Wifi my local MQTT broker are required to run application code. The connection to the cloud is optional. I obviously want a could connection for flashing code and debugging tools, if my home internet is down then the devices should still operate on the LAN with no internet access needed.
To accomplish decoupling the WiFi connection from the Cloud connection I’m going to use SYSTEM_MODE(MANUAL). To keep the Cloud connection from blocking the device I’m going to run SYSTEM_THREAD(ENABLED). Because I’m running a separate thread I’ll need to take care that I’m not using long delays and instead using short delays in a loop while calling Particle.Process()
Algorithm Summary
- If the Wifi is in listening mode then just delay 50, run Particle.Process() and get out.
- If we don’t have a Wifi Connection then call connect and wait for up to 60 seconds.
- If Wifi failed to connect 60 consecutive times then reboot the device
- If we established a Wifi connection then call Particle.connect(), but only once every 30 seconds. And no penalty if it doesn’t work.
- Connect to the MQTT broker. If it fails then wait 60 seconds before trying again
- If MQTT failed to connect 60 consecutive times then reboot the device
Notes:
In all cases we only run the application code if we have Wifi & MQTT.
In any delay loop we run Particle.Process() and also check if the device en tered listening mode (hold setup for 3 seconds).
In one version of my code the connect to the MQTT server became blocking infinitely. I think it had to do with running out of sockets. Any comments?
The Code
unsigned long now = millis();
connectionState = (WiFi.ready() ? 1 : 0) + (MQTT::isConnected() ? 2 : 0) + (Particle.connected() ? 4 : 0);
// 5 seconds pass, log connection state
if( lastConnectionLog == -1 || (now - lastConnectionLog) > 5000)
{
lastConnectionLog = now;
log("boot", "Connection State: ", String(connectionState));
if(WiFi.connecting())
log("boot", "WiFi.connecting...");
if(WiFi.listening())
log("boot", "WiFi.listening...");
}
// Particle is in setup mode. don't run app code.
if(WiFi.listening())
{
Particle.process();
delay(50);
return;
}
// Connect to Wifi or restart
if (!WiFi.ready())
{
log("boot", "Connecting to WiFi...", String(connectionState));
lastParticleConnect = -1;
lastParticleCloud = false;
WiFi.connect();
int waitCounter = 60000; // ~60 seconds
while(waitCounter > 0 && (!WiFi.ready()))
{
Particle.process();
if(WiFi.listening()) return;
delay(50);
waitCounter -= 50;
}
if(WiFi.ready())
{
log("boot", "Connected to local WiFi...", String(connectionState));
log("boot", "WiFi localIP", WiFi.localIP().toString());
log("boot", "WiFi subnetMask", WiFi.subnetMask().toString());
log("boot", "WiFi gatewayIP", WiFi.gatewayIP().toString());
log("boot", "WiFi dnsServerIP", WiFi.dnsServerIP().toString());
log("boot", "WiFi dhcpServerIP", WiFi.dhcpServerIP().toString());
log("boot", "wifi signal online ", WiFi.SSID());
}
else
{
log("boot", "No Wifi Connection");
wifiFailConnections++;
if(wifiFailConnections > 60)
{
log("boot", "No Wifi in 60 minutes - restart");
Particle.process();
System.reset(); //Epic fail bro
}
}
return;
}
// Try a Particle Connect every 30 seconds
// Ok to run without cloud, but keep trying
if ((!Particle.connected()) && (lastParticleConnect == -1 || ((now - lastParticleConnect) > 30000)))
{
log("boot", "Connecting to Particle Cloud...", String(connectionState));
lastParticleConnect = now;
lastParticleCloud = false;
Particle.connect();
Particle.process();
}
if (Particle.connected() && (!lastParticleCloud))
{
log("boot", "Connected to Particle Cloud...", String(connectionState));
lastParticleCloud = true;
lastParticleConnect = -1;
}
if (!MQTT::isConnected()) {
log("boot", "Connecting to MQTT Server...", String(connectionState));
if (MQTT::connect(devicename.c_str(), mqttusername.c_str(), mqttpassword.c_str(), statusTopic, QOS0, 0, "{\"value\": false}", 0))
{
log("boot", "Connecting to ", this->mqttserver.c_str());
mqttFailConnections = 0;
// Subscribe to commands for all sensors for this device
MQTT::subscribe(subscribeCmdTopic, QOS1);
MQTT::publish(statusTopic, "{\"value\": true}");
MQTT::loop();
}
else
{
log("boot", "No MQTT Connection");
mqttFailConnections++;
int waitCounter = 60000; // ~60 seconds
while(waitCounter > 0)
{
Particle.process();
if(WiFi.listening()) return;
delay(50);
waitCounter -= 50;
}
// Can't connect to MQTT Server. reboot and try again
if(mqttFailConnections > 60)
{
log("boot", "60 MQTT Failures - restarting...");
System.reset(); //Epic fail bro
}
return;
}
}
APPLICATION CODE HERE...