Skip to content

Commit

Permalink
Merge pull request #116 from adafruit/network-check-res
Browse files Browse the repository at this point in the history
Fix non-blocking network timeouts
  • Loading branch information
brentru authored Aug 11, 2021
2 parents 7c00810 + 443b7c2 commit db4049e
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 71 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ WipperSnapper currently supports the following hardware. Don't see your board? D

ESP32-S2
* Adafruit FunHouse
* Adafruit MagTag 2.9"
* Adafruit Metro ESP32-S2

SAMD51
* Adafruit Metro M4 AirLift Lite
Expand Down
118 changes: 52 additions & 66 deletions src/Wippersnapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -856,51 +856,6 @@ void Wippersnapper::set_ssid_pass() {
WS_DEBUG_PRINTLN("ERROR: Please define a network interface!");
}

/**************************************************************************/
/*!
@brief Checks and handles network interface connection.
@returns Network status as ws_status_t.
*/
/**************************************************************************/
ws_status_t Wippersnapper::checkNetworkConnection() {
if (status() < WS_NET_CONNECTED) {
WS_DEBUG_PRINTLN("WiFi connection failed out, reconnecting...");
unsigned long startRetry = millis();
connect();
while (status() < WS_CONNECTED) { // return an error on timeout
if (millis() - startRetry > 60000) {
return status();
}
delay(500);
}
}
return status();
}

/**************************************************************************/
/*!
@brief Handles MQTT connection.
@param timeStart
The time which this function was called, in milliseconds.
@returns Network status, as ws_status_t.
*/
/**************************************************************************/
ws_status_t Wippersnapper::checkMQTTConnection(uint32_t timeStart) {
// Return quickly
if (mqttStatus() == WS_CONNECTED) {
return status();
}

// loop until we have a connection
// mqttStatus() will try to reconnect before returning
while (mqttStatus() != WS_CONNECTED && millis() - timeStart < 60000) {
}
if (mqttStatus() != WS_CONNECTED) {
WS_DEBUG_PRINTLN("ERROR: Disconnected from MQTT!");
}
return status();
}

/**************************************************************************/
/*!
@brief Pings MQTT broker.
Expand Down Expand Up @@ -952,23 +907,25 @@ bool Wippersnapper::encodePinEvent(
*/
/**************************************************************************/
ws_status_t Wippersnapper::run() {
// this should be a state machine, dept. on the network...

// WS_DEBUG_PRINTLN("exec::run()");
uint32_t curTime = millis();

// Handle network connection
checkNetworkConnection();
// Handle MQTT connection
checkMQTTConnection(curTime);
// Handle networking
handleNetworking();
feedWDT();

// Process all incoming packets from Wippersnapper MQTT Broker
WS._mqtt->processPackets(10);
feedWDT();

// Process digital inputs, digitalGPIO module
WS._digitalGPIO->processDigitalInputs();
feedWDT();

// Process analog inputs
WS._analogIO->processAnalogInputs();

feedWDT();

return status();
Expand Down Expand Up @@ -1012,6 +969,45 @@ ws_status_t Wippersnapper::status() {
return _status;
}

void Wippersnapper::handleNetworking() {
bool mqttDisconnected = false;
// Handle WiFi connection, BLOCKING
while (keepAliveWiFi() != WS_NET_CONNECTED) {
setStatusLEDColor(LED_ERROR);
WS_DEBUG_PRINT("Network Status: ");
WS_DEBUG_PRINTLN(networkStatus());
delay(20000);
feedWDT();
};
// Handle MQTT connection, BLOCKING
while (mqttStatus() != WS_CONNECTED) {
setStatusLEDColor(LED_ERROR);
WS_DEBUG_PRINT("MQTT Error: ");
WS_DEBUG_PRINTLN(WS._mqtt->connectErrorString(_status));
mqttDisconnected = true;
delay(20000);
feedWDT();
}
// Perform re-registration if we disconnect from MQTT broker as well
if (mqttDisconnected)
registerBoard(10);
}

ws_status_t Wippersnapper::keepAliveWiFi() {
WS_DEBUG_PRINTLN("keepAliveWiFi()");
if (networkStatus() == WS_NET_CONNECTED) {
if (usingStatusNeoPixel)
statusLEDDeinit();
return WS_NET_CONNECTED; // return immediately if WL_CONNECTED
}
// Otherwise, try to reconnect
WS_DEBUG_PRINTLN("Attempting to reconnect...");
feedWDT();
setStatusLEDColor(LED_NET_CONNECT);
_connect();
return networkStatus();
}

/**************************************************************************/
/*!
@brief Returns the board definition status
Expand All @@ -1027,19 +1023,7 @@ ws_board_status_t Wippersnapper::getBoardStatus() { return WS._boardStatus; }
*/
/**************************************************************************/
ws_status_t Wippersnapper::mqttStatus() {
// if the connection failed,
// return so we don't hammer IO
if (_status == WS_CONNECT_FAILED) {
WS_DEBUG_PRINT("mqttStatus() failed to connect");
#ifdef USE_TINYUSB
WS._fileSystem->writeErrorToBootOut(
"ERROR: Failed to connect to WipperSnapper, retrying...");
#endif
WS_DEBUG_PRINTLN(WS._mqtt->connectErrorString(_status));
setStatusLEDColor(LED_ERROR);
return _status;
}

// First, handle the case where we're connected
if (WS._mqtt->connected()) {
// ping within keepalive to keep connection open
if (millis() > (_prv_ping + WS_KEEPALIVE_INTERVAL_MS)) {
Expand All @@ -1049,7 +1033,8 @@ ws_status_t Wippersnapper::mqttStatus() {
// blink status LED every STATUS_LED_KAT_BLINK_TIME millis
if (millis() > (_prvKATBlink + STATUS_LED_KAT_BLINK_TIME)) {
if (!statusLEDInit()) {
WS_DEBUG_PRINTLN("Can not blink, status-LED in use");
WS_DEBUG_PRINTLN(
"Can not blink, status-LED in use by WipperSnapper Application");
} else {
statusLEDBlink(WS_LED_STATUS_KAT);
statusLEDDeinit();
Expand All @@ -1059,10 +1044,11 @@ ws_status_t Wippersnapper::mqttStatus() {
return WS_CONNECTED;
}

// prevent fast reconnect attempts, except for the first time through
// Next, handle the case where we are not connected and attempt to reconnect
if (_last_mqtt_connect == 0 ||
millis() - _last_mqtt_connect > WS_KEEPALIVE_INTERVAL_MS) {
_last_mqtt_connect = millis();
setStatusLEDColor(LED_IO_CONNECT);
switch (WS._mqtt->connect(WS._username, WS._key)) {
case 0:
return WS_CONNECTED;
Expand Down Expand Up @@ -1115,4 +1101,4 @@ void Wippersnapper::enableWDT(int timeoutMS) {
}
}
#endif
}
}
5 changes: 5 additions & 0 deletions src/Wippersnapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ class Wippersnapper {
virtual void setupMQTTClient(const char *clientID);

virtual ws_status_t networkStatus();
ws_status_t keepAliveWiFi();
ws_status_t status();
ws_status_t mqttStatus();
ws_board_status_t getBoardStatus();
Expand All @@ -210,7 +211,11 @@ class Wippersnapper {
ws_status_t run();
ws_status_t checkNetworkConnection();
ws_status_t checkMQTTConnection(uint32_t timeStart);
// Networking
void handleNetworking();
void ping();

// WDT
void enableWDT(int timeoutMS = 0);
void feedWDT();

Expand Down
14 changes: 9 additions & 5 deletions src/network_interfaces/Wippersnapper_ESP32.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,16 @@ class Wippersnapper_ESP32 : public Wippersnapper {
_status = WS_NET_DISCONNECTED;
}

// wait until connection is established
while (WiFi.status() != WL_CONNECTED) {
delay(100);
// wait for connection to be established
long startRetry = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startRetry < 10000) {
// do nothing, busy loop during the timeout
}
// timeout expired and connected
if (WiFi.status() == WL_CONNECTED) {
_mqtt_client->setCACert(_aio_root_ca);
return;
}

_mqtt_client->setCACert(_aio_root_ca);
}

/**************************************************************************/
Expand Down

0 comments on commit db4049e

Please sign in to comment.