From 4639a9fbad09e1c155a1c84a3a68df269e1c62fd Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Sun, 17 Nov 2019 08:35:11 -0500 Subject: [PATCH 01/15] Detect dropped network connection Check networkStatus() in mqttStatus() before attempting to reconnect MQTT. Fail quickly to avoid the ~20 seconds for MQTT connect attempts to timeout. Allow run() to return if the MQTT connection is down, without any other action. The calling sketch can then check network status, etc. to fix the problem. Checking mqttStatus() once per loop() is enough to allow it to retry the MQTT connection when needed. https://github.com/adafruit/Adafruit_IO_Arduino/issues/99 --- src/AdafruitIO.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 318715fc..b0c16522 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -167,8 +167,8 @@ const __FlashStringHelper* AdafruitIO::statusText() void AdafruitIO::run(uint16_t busywait_ms) { - // loop until we have a connection - while(mqttStatus() != AIO_CONNECTED){} + // mqttStatus() will try to reconnect before returning + if(mqttStatus() != AIO_CONNECTED) return; if(busywait_ms > 0) _packetread_timeout = busywait_ms; @@ -239,6 +239,13 @@ aio_status_t AdafruitIO::mqttStatus() return _status; } + aio_status_t net_status = networkStatus(); + // if we aren't connected, return network status -- fail quickly + if(net_status != AIO_NET_CONNECTED) { + _status = net_status; + return _status; + } + if(_mqtt->connected()) return AIO_CONNECTED; From f3d1eb6694bece24bd00ea0b79dff65835deb9e7 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Sun, 17 Nov 2019 11:13:43 -0500 Subject: [PATCH 02/15] allow mqttStatus() to return without waiting for connection Old version would delay(AIO_THROTTLE_RECONNECT_INTERVAL) before returning. This could leave the sketch stuck in limbo for 60 seconds. Modification remembers last try at connection and doesn't try again until the interval has passed. --- src/AdafruitIO.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index b0c16522..59f00a49 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -230,7 +230,8 @@ char* AdafruitIO::userAgent() aio_status_t AdafruitIO::mqttStatus() { - // if the connection failed, + static uint32_t lastTried = 0; // remember last attempt to connect + // if the connection irretrievably failed, // return so we don't hammer IO if(_status == AIO_CONNECT_FAILED) { @@ -248,7 +249,12 @@ aio_status_t AdafruitIO::mqttStatus() if(_mqtt->connected()) return AIO_CONNECTED; + + // don't try to connect more often than the throttle interval + if(lastTried != 0 && millis() < (lastTried + AIO_THROTTLE_RECONNECT_INTERVAL)) + return AIO_DISCONNECTED; + lastTried = millis(); switch(_mqtt->connect(_username, _key)) { case 0: return AIO_CONNECTED; @@ -260,8 +266,6 @@ aio_status_t AdafruitIO::mqttStatus() case 3: // mqtt service unavailable case 6: // throttled case 7: // banned -> all MQTT bans are temporary, so eventual retry is permitted - // delay to prevent fast reconnects - delay(AIO_THROTTLE_RECONNECT_INTERVAL); return AIO_DISCONNECTED; default: return AIO_DISCONNECTED; From c99b2346cbc410345feeb8a2d1785936038aacc6 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Sun, 17 Nov 2019 11:17:22 -0500 Subject: [PATCH 03/15] add comment --- src/AdafruitIO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 59f00a49..28c0283b 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -250,7 +250,7 @@ aio_status_t AdafruitIO::mqttStatus() if(_mqtt->connected()) return AIO_CONNECTED; - // don't try to connect more often than the throttle interval + // Unless it's the first time, don't try to connect more often than the throttle interval if(lastTried != 0 && millis() < (lastTried + AIO_THROTTLE_RECONNECT_INTERVAL)) return AIO_DISCONNECTED; From 3531a8b4507ef9296e9c6cc9f748b4ae78bd2596 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Sun, 17 Nov 2019 14:01:08 -0500 Subject: [PATCH 04/15] Update AdafruitIO.cpp --- src/AdafruitIO.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 28c0283b..dfc448dd 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -42,6 +42,7 @@ void AdafruitIO::connect() if(_err_sub) { // setup error sub + Serial.print("setting up err_sub\n"); _err_sub = new Adafruit_MQTT_Subscribe(_mqtt, _err_topic); _mqtt->subscribe(_err_sub); _err_sub->setCallback(errorCallback); From abd05e1f3022c463b7fb814027d128d997709fee Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Sun, 17 Nov 2019 14:04:55 -0500 Subject: [PATCH 05/15] Revert "Update AdafruitIO.cpp" This reverts commit 3531a8b4507ef9296e9c6cc9f748b4ae78bd2596. --- src/AdafruitIO.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index dfc448dd..28c0283b 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -42,7 +42,6 @@ void AdafruitIO::connect() if(_err_sub) { // setup error sub - Serial.print("setting up err_sub\n"); _err_sub = new Adafruit_MQTT_Subscribe(_mqtt, _err_topic); _mqtt->subscribe(_err_sub); _err_sub->setCallback(errorCallback); From e1a523337c00e057e3f4fee6b156ab8b9b97e8d7 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Mon, 9 Dec 2019 14:29:49 -0500 Subject: [PATCH 06/15] Revert "add comment" This reverts commit c99b2346cbc410345feeb8a2d1785936038aacc6. --- src/AdafruitIO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 28c0283b..59f00a49 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -250,7 +250,7 @@ aio_status_t AdafruitIO::mqttStatus() if(_mqtt->connected()) return AIO_CONNECTED; - // Unless it's the first time, don't try to connect more often than the throttle interval + // don't try to connect more often than the throttle interval if(lastTried != 0 && millis() < (lastTried + AIO_THROTTLE_RECONNECT_INTERVAL)) return AIO_DISCONNECTED; From 5d0c2afba7f64039504f6ed824ac19b39077cd81 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Mon, 9 Dec 2019 14:29:55 -0500 Subject: [PATCH 07/15] Revert "allow mqttStatus() to return without waiting for connection" This reverts commit f3d1eb6694bece24bd00ea0b79dff65835deb9e7. --- src/AdafruitIO.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 59f00a49..b0c16522 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -230,8 +230,7 @@ char* AdafruitIO::userAgent() aio_status_t AdafruitIO::mqttStatus() { - static uint32_t lastTried = 0; // remember last attempt to connect - // if the connection irretrievably failed, + // if the connection failed, // return so we don't hammer IO if(_status == AIO_CONNECT_FAILED) { @@ -249,12 +248,7 @@ aio_status_t AdafruitIO::mqttStatus() if(_mqtt->connected()) return AIO_CONNECTED; - - // don't try to connect more often than the throttle interval - if(lastTried != 0 && millis() < (lastTried + AIO_THROTTLE_RECONNECT_INTERVAL)) - return AIO_DISCONNECTED; - lastTried = millis(); switch(_mqtt->connect(_username, _key)) { case 0: return AIO_CONNECTED; @@ -266,6 +260,8 @@ aio_status_t AdafruitIO::mqttStatus() case 3: // mqtt service unavailable case 6: // throttled case 7: // banned -> all MQTT bans are temporary, so eventual retry is permitted + // delay to prevent fast reconnects + delay(AIO_THROTTLE_RECONNECT_INTERVAL); return AIO_DISCONNECTED; default: return AIO_DISCONNECTED; From 8edac233b3f4b30dff1456b1d88bf8a38fa3d53a Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Mon, 9 Dec 2019 14:33:25 -0500 Subject: [PATCH 08/15] Revert "Detect dropped network connection" This reverts commit 4639a9fbad09e1c155a1c84a3a68df269e1c62fd. --- src/AdafruitIO.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index b0c16522..318715fc 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -167,8 +167,8 @@ const __FlashStringHelper* AdafruitIO::statusText() void AdafruitIO::run(uint16_t busywait_ms) { - // mqttStatus() will try to reconnect before returning - if(mqttStatus() != AIO_CONNECTED) return; + // loop until we have a connection + while(mqttStatus() != AIO_CONNECTED){} if(busywait_ms > 0) _packetread_timeout = busywait_ms; @@ -239,13 +239,6 @@ aio_status_t AdafruitIO::mqttStatus() return _status; } - aio_status_t net_status = networkStatus(); - // if we aren't connected, return network status -- fail quickly - if(net_status != AIO_NET_CONNECTED) { - _status = net_status; - return _status; - } - if(_mqtt->connected()) return AIO_CONNECTED; From 51d3096b7f18bc0af799bfcb6683b1af155fb16f Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Mon, 9 Dec 2019 15:20:43 -0500 Subject: [PATCH 09/15] io.run now returns status, doesn't hang This walks back my more agreesive solution in the interest of backwards compatibility. It provides a new example that protects against dropped network connections. --- .../adafruitio_02_pubsub_protected.ino | 117 ++++++++++++++++++ .../adafruitio_02_pubsub_protected/config.h | 67 ++++++++++ src/AdafruitIO.cpp | 13 +- src/AdafruitIO.h | 2 +- 4 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino create mode 100644 examples/adafruitio_02_pubsub_protected/config.h diff --git a/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino b/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino new file mode 100644 index 00000000..d25dbd18 --- /dev/null +++ b/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino @@ -0,0 +1,117 @@ +// Adafruit IO Publish/Subscribe Example with Protection +// +// Adafruit invests time and resources providing this open source code. +// Please support Adafruit and open source hardware by purchasing +// products from Adafruit! +// +// Written by Todd Treece for Adafruit Industries +// Copyright (c) 2016 Adafruit Industries +// Licensed under the MIT license. +// +// All text above must be included in any redistribution. + +/************************** Configuration ***********************************/ +// Comment out if you do not maintain an ssid.h file for your personal credentials. +// Then add your own credentials in the config.h tab. +#include "ssid.h" + +// edit the config.h tab and enter your Adafruit IO credentials +// and any additional configuration needed for WiFi, cellular, +// or ethernet clients. +#include "config.h" + +/************************ Example Starts Here *******************************/ +// This pub/sub example tests the status and reconnects if the network goes down. + +// this int will hold the current count for our sketch +int count = 0; + +// set up the 'counter' feed +AdafruitIO_Feed *counter = io.feed("counter"); +// https://io.adafruit.com/api/docs/mqtt.html#username-errors +//AdafruitIO_Feed *throttles = io.feed("throttle"); +//AdafruitIO_Feed *errors = io.feed("errors"); + +void setup() { + + // start the serial connection + Serial.begin(115200); + + // wait for serial monitor to open + while(! Serial); + + setupIO(); +} + +void setupIO() { + Serial.print("Connecting to Adafruit IO"); + + // connect to io.adafruit.com -- must be called before any other io calls! + // calling io.status() first will make the subsequent connection attempt fail. + io.connect(); + counter->onMessage(handleMessage); + + // wait for a connection + unsigned long started = millis(); + while(io.status() < AIO_CONNECTED) { + if(millis() - started > 30000){ + started = millis(); + io.connect(); // try again if you run out of patience + } + Serial.print("."); + delay(500); + } + + // we are connected + Serial.println(); + Serial.println(io.statusText()); + counter->get(); // https://io.adafruit.com/api/docs/mqtt.html#using-the-get-topic +} + +void handleMessage(AdafruitIO_Data *data) { + Serial.print("\nreceived <- "); + Serial.println(data->value()); +} + +void loop() { + + // io.run(); is required for all sketches. + // it should always be present at the top of your loop + // function. it keeps the client connected to + // io.adafruit.com, and processes any incoming data. + if(millis()%60000 > 30000){ + WiFi.disconnect(); // Wifi will die in the top half of every minute + delay(300); // wait a while for the disaster to show... + } + Serial.print("\n\nTop of Loop!\nio.status: ");Serial.print(io.status()); + Serial.print(": "); Serial.print(io.statusText()); Serial.print("\n"); + Serial.print("io.networkStatus: "); Serial.print(io.networkStatus()); Serial.print("\n"); + Serial.print("io.mqttStatus: "); Serial.print(io.mqttStatus()); Serial.print("\n"); + Serial.print("WiFi.status: "); Serial.print(WiFi.status()); Serial.print("\n"); + + // Here's where we check the network and start over if it has lost connection + if(io.status() < AIO_NET_CONNECTED){ + Serial.print("Not Net Connected to IO!!! Reconnect!!!\n\n"); + count++; + setupIO(); //Start IO all over again + } + + Serial.print("Calling io.run()..."); // io.run() will hang if network disconnected 2019-11-16 + io.run(); // process messages and keep connection alive + Serial.print("Done\n"); + + // save count to the 'counter' feed on Adafruit IO + Serial.print("sending -> "); + Serial.print(count); + if(counter->save(count)) Serial.print(" sent!"); + else Serial.print(" failed to send!"); + + // Adafruit IO is rate limited for publishing, so a delay is required in + // between feed->save events. In this example, we will wait three seconds + // (1000 milliseconds == 1 second) during each loop. + // Adding the if statement allows you to generate a burst of faster saves + // to generate some throttling events and see how the code responds. + if(millis() < 90000 || millis() > 120000) delay(3000); + else delay(5000); + +} diff --git a/examples/adafruitio_02_pubsub_protected/config.h b/examples/adafruitio_02_pubsub_protected/config.h new file mode 100644 index 00000000..517161d3 --- /dev/null +++ b/examples/adafruitio_02_pubsub_protected/config.h @@ -0,0 +1,67 @@ +/************************ Adafruit IO Config *******************************/ + +// visit io.adafruit.com if you need to create an account, +// or if you need your Adafruit IO key. +// Uncomment these lines and add your own credentials if needed +//#define IO_USERNAME "your_username" +//#define IO_KEY "your_key" + +/******************************* WIFI **************************************/ + +// the AdafruitIO_WiFi client will work with the following boards: +// - HUZZAH ESP8266 Breakout -> https://www.adafruit.com/products/2471 +// - Feather HUZZAH ESP8266 -> https://www.adafruit.com/products/2821 +// - Feather HUZZAH ESP32 -> https://www.adafruit.com/product/3405 +// - Feather M0 WiFi -> https://www.adafruit.com/products/3010 +// - Feather WICED -> https://www.adafruit.com/products/3056 +// - Adafruit PyPortal -> https://www.adafruit.com/product/4116 +// - Adafruit Metro M4 Express AirLift Lite -> https://www.adafruit.com/product/4000 +// - Adafruit AirLift Breakout -> https://www.adafruit.com/product/4201 +// - Adafruit AirLift Shield -> https://www.adafruit.com/product/4285 +// - Adafruit AirLift FeatherWing -> https://www.adafruit.com/product/4264 + +//#define WIFI_SSID "your_ssid" +//#define WIFI_PASS "your_pass" + +// uncomment the following line if you are using airlift +// #define USE_AIRLIFT + +// uncomment the following line if you are using winc1500 +#define USE_WINC1500 + +// comment out the following lines if you are using fona or ethernet +#include "AdafruitIO_WiFi.h" + +#if defined(USE_AIRLIFT) || defined(ADAFRUIT_METRO_M4_AIRLIFT_LITE) + // Configure the pins used for the ESP32 connection + #if !defined(SPIWIFI_SS) // if the wifi definition isnt in the board variant + // Don't change the names of these #define's! they match the variant ones + #define SPIWIFI SPI + #define SPIWIFI_SS 10 // Chip select pin + #define NINA_ACK 9 // a.k.a BUSY or READY pin + #define NINA_RESETN 6 // Reset pin + #define NINA_GPIO0 -1 // Not connected + #endif + AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS, SPIWIFI_SS, NINA_ACK, NINA_RESETN, NINA_GPIO0, &SPIWIFI); +#else + AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS); +#endif +/******************************* FONA **************************************/ + +// the AdafruitIO_FONA client will work with the following boards: +// - Feather 32u4 FONA -> https://www.adafruit.com/product/3027 + +// uncomment the following two lines for 32u4 FONA, +// and comment out the AdafruitIO_WiFi client in the WIFI section +// #include "AdafruitIO_FONA.h" +// AdafruitIO_FONA io(IO_USERNAME, IO_KEY); + +/**************************** ETHERNET ************************************/ + +// the AdafruitIO_Ethernet client will work with the following boards: +// - Ethernet FeatherWing -> https://www.adafruit.com/products/3201 + +// uncomment the following two lines for ethernet, +// and comment out the AdafruitIO_WiFi client in the WIFI section +// #include "AdafruitIO_Ethernet.h" +// AdafruitIO_Ethernet io(IO_USERNAME, IO_KEY); diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 318715fc..0bdf984b 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -165,9 +165,18 @@ const __FlashStringHelper* AdafruitIO::statusText() } } -void AdafruitIO::run(uint16_t busywait_ms) +aio_status_t AdafruitIO::run(uint16_t busywait_ms) { + aio_status_t net_status = networkStatus(); + // If we aren't connected, return network status -- fail quickly + // Previous version would just hang on a network error + if(net_status != AIO_NET_CONNECTED) { + _status = net_status; + return _status; + } + // loop until we have a connection + // mqttStatus() will try to reconnect before returning while(mqttStatus() != AIO_CONNECTED){} if(busywait_ms > 0) @@ -241,7 +250,7 @@ aio_status_t AdafruitIO::mqttStatus() if(_mqtt->connected()) return AIO_CONNECTED; - + switch(_mqtt->connect(_username, _key)) { case 0: return AIO_CONNECTED; diff --git a/src/AdafruitIO.h b/src/AdafruitIO.h index a5145e0b..51facc5b 100644 --- a/src/AdafruitIO.h +++ b/src/AdafruitIO.h @@ -45,7 +45,7 @@ class AdafruitIO { virtual ~AdafruitIO(); void connect(); - void run(uint16_t busywait_ms = 0); + aio_status_t run(uint16_t busywait_ms = 0); AdafruitIO_Feed* feed(const char *name); AdafruitIO_Feed* feed(const char *name, const char *owner); From 246a482e9365e3b3ab19bcd90e26cf0e771a6566 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Mon, 9 Dec 2019 15:34:04 -0500 Subject: [PATCH 10/15] add return to io.run() --- src/AdafruitIO.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 0bdf984b..83f1c2c4 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -189,6 +189,7 @@ aio_status_t AdafruitIO::run(uint16_t busywait_ms) _mqtt->ping(); _last_ping = millis(); } + return _status; } aio_status_t AdafruitIO::status() From 57e0ba99dee0b9c8b4ce8e69f45523e94d5272a0 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Mon, 9 Dec 2019 15:57:39 -0500 Subject: [PATCH 11/15] add timeout in io.run() io.run will now return after a very long timeout instead of just hanging --- src/AdafruitIO.cpp | 4 +++- src/AdafruitIO.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 83f1c2c4..37bb4fcb 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -167,6 +167,7 @@ const __FlashStringHelper* AdafruitIO::statusText() aio_status_t AdafruitIO::run(uint16_t busywait_ms) { + uint32_t timeStart = millis(); aio_status_t net_status = networkStatus(); // If we aren't connected, return network status -- fail quickly // Previous version would just hang on a network error @@ -177,7 +178,8 @@ aio_status_t AdafruitIO::run(uint16_t busywait_ms) // loop until we have a connection // mqttStatus() will try to reconnect before returning - while(mqttStatus() != AIO_CONNECTED){} + while(mqttStatus() != AIO_CONNECTED && millis() - timeStart < ADAFRUITIO_RUN_TIMEOUT){} + if(mqttStatus() != AIO_CONNECTED) return _status; if(busywait_ms > 0) _packetread_timeout = busywait_ms; diff --git a/src/AdafruitIO.h b/src/AdafruitIO.h index 51facc5b..c6f2e72f 100644 --- a/src/AdafruitIO.h +++ b/src/AdafruitIO.h @@ -12,6 +12,10 @@ #ifndef ADAFRUITIO_H #define ADAFRUITIO_H +#ifndef ADAFRUITIO_RUN_TIMEOUT +#define ADAFRUITIO_RUN_TIMEOUT 60000 +#endif + #include "Arduino.h" #include "Adafruit_MQTT.h" #include "AdafruitIO_Definitions.h" From 5ebff21d1ddd5c88760d93ebd53773773812e4b8 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Mon, 9 Dec 2019 18:42:35 -0500 Subject: [PATCH 12/15] Update adafruitio_02_pubsub_protected.ino Switched to use io.run() for status checking. Comments and formatting --- .../adafruitio_02_pubsub_protected.ino | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino b/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino index d25dbd18..35a30dcc 100644 --- a/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino +++ b/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino @@ -28,9 +28,6 @@ int count = 0; // set up the 'counter' feed AdafruitIO_Feed *counter = io.feed("counter"); -// https://io.adafruit.com/api/docs/mqtt.html#username-errors -//AdafruitIO_Feed *throttles = io.feed("throttle"); -//AdafruitIO_Feed *errors = io.feed("errors"); void setup() { @@ -44,6 +41,8 @@ void setup() { } void setupIO() { + // these operations are specific the AdafruitIO connection and may be repeated + // if the connection fails. https://github.com/adafruit/Adafruit_IO_Arduino/issues/99 Serial.print("Connecting to Adafruit IO"); // connect to io.adafruit.com -- must be called before any other io calls! @@ -74,36 +73,35 @@ void handleMessage(AdafruitIO_Data *data) { } void loop() { - - // io.run(); is required for all sketches. - // it should always be present at the top of your loop - // function. it keeps the client connected to - // io.adafruit.com, and processes any incoming data. + // for this test we will disconnect the WiFi and watch how statuses change -- not normal operations if(millis()%60000 > 30000){ WiFi.disconnect(); // Wifi will die in the top half of every minute delay(300); // wait a while for the disaster to show... } - Serial.print("\n\nTop of Loop!\nio.status: ");Serial.print(io.status()); - Serial.print(": "); Serial.print(io.statusText()); Serial.print("\n"); - Serial.print("io.networkStatus: "); Serial.print(io.networkStatus()); Serial.print("\n"); - Serial.print("io.mqttStatus: "); Serial.print(io.mqttStatus()); Serial.print("\n"); - Serial.print("WiFi.status: "); Serial.print(WiFi.status()); Serial.print("\n"); + Serial.print("\n\nTop of Loop!\n"); + Serial.print(" io.status(): "); Serial.print(io.status()); + Serial.print(" -- "); Serial.print(io.statusText()); Serial.print("\n"); + Serial.print("io.networkStatus(): "); Serial.print(io.networkStatus()); Serial.print("\n"); + Serial.print(" io.mqttStatus(): "); Serial.print(io.mqttStatus()); Serial.print("\n"); + Serial.print(" WiFi.status(): "); Serial.print(WiFi.status()); Serial.print("\n"); + // io.run(); is required for all sketches. + // it should always be present at the top of your loop + // function. it keeps the client connected to + // io.adafruit.com, and processes any incoming data. // Here's where we check the network and start over if it has lost connection - if(io.status() < AIO_NET_CONNECTED){ - Serial.print("Not Net Connected to IO!!! Reconnect!!!\n\n"); - count++; - setupIO(); //Start IO all over again - } - Serial.print("Calling io.run()..."); // io.run() will hang if network disconnected 2019-11-16 - io.run(); // process messages and keep connection alive + if(io.run() < AIO_NET_CONNECTED){ + Serial.print("No Network Connection!!! Reconnect!!!\n"); + count++; // count network restarts + setupIO(); // Start IO all over again + } Serial.print("Done\n"); // save count to the 'counter' feed on Adafruit IO Serial.print("sending -> "); Serial.print(count); - if(counter->save(count)) Serial.print(" sent!"); + if(counter->save(count)) Serial.print(" sent! (no proof of receipt)"); else Serial.print(" failed to send!"); // Adafruit IO is rate limited for publishing, so a delay is required in From 350bb8951e8af42f0c1532996168cbe0e2d1fab5 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Mon, 9 Dec 2019 19:08:27 -0500 Subject: [PATCH 13/15] Remove example --- .../adafruitio_02_pubsub_protected.ino | 115 ------------------ .../adafruitio_02_pubsub_protected/config.h | 67 ---------- 2 files changed, 182 deletions(-) delete mode 100644 examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino delete mode 100644 examples/adafruitio_02_pubsub_protected/config.h diff --git a/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino b/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino deleted file mode 100644 index 35a30dcc..00000000 --- a/examples/adafruitio_02_pubsub_protected/adafruitio_02_pubsub_protected.ino +++ /dev/null @@ -1,115 +0,0 @@ -// Adafruit IO Publish/Subscribe Example with Protection -// -// Adafruit invests time and resources providing this open source code. -// Please support Adafruit and open source hardware by purchasing -// products from Adafruit! -// -// Written by Todd Treece for Adafruit Industries -// Copyright (c) 2016 Adafruit Industries -// Licensed under the MIT license. -// -// All text above must be included in any redistribution. - -/************************** Configuration ***********************************/ -// Comment out if you do not maintain an ssid.h file for your personal credentials. -// Then add your own credentials in the config.h tab. -#include "ssid.h" - -// edit the config.h tab and enter your Adafruit IO credentials -// and any additional configuration needed for WiFi, cellular, -// or ethernet clients. -#include "config.h" - -/************************ Example Starts Here *******************************/ -// This pub/sub example tests the status and reconnects if the network goes down. - -// this int will hold the current count for our sketch -int count = 0; - -// set up the 'counter' feed -AdafruitIO_Feed *counter = io.feed("counter"); - -void setup() { - - // start the serial connection - Serial.begin(115200); - - // wait for serial monitor to open - while(! Serial); - - setupIO(); -} - -void setupIO() { - // these operations are specific the AdafruitIO connection and may be repeated - // if the connection fails. https://github.com/adafruit/Adafruit_IO_Arduino/issues/99 - Serial.print("Connecting to Adafruit IO"); - - // connect to io.adafruit.com -- must be called before any other io calls! - // calling io.status() first will make the subsequent connection attempt fail. - io.connect(); - counter->onMessage(handleMessage); - - // wait for a connection - unsigned long started = millis(); - while(io.status() < AIO_CONNECTED) { - if(millis() - started > 30000){ - started = millis(); - io.connect(); // try again if you run out of patience - } - Serial.print("."); - delay(500); - } - - // we are connected - Serial.println(); - Serial.println(io.statusText()); - counter->get(); // https://io.adafruit.com/api/docs/mqtt.html#using-the-get-topic -} - -void handleMessage(AdafruitIO_Data *data) { - Serial.print("\nreceived <- "); - Serial.println(data->value()); -} - -void loop() { - // for this test we will disconnect the WiFi and watch how statuses change -- not normal operations - if(millis()%60000 > 30000){ - WiFi.disconnect(); // Wifi will die in the top half of every minute - delay(300); // wait a while for the disaster to show... - } - Serial.print("\n\nTop of Loop!\n"); - Serial.print(" io.status(): "); Serial.print(io.status()); - Serial.print(" -- "); Serial.print(io.statusText()); Serial.print("\n"); - Serial.print("io.networkStatus(): "); Serial.print(io.networkStatus()); Serial.print("\n"); - Serial.print(" io.mqttStatus(): "); Serial.print(io.mqttStatus()); Serial.print("\n"); - Serial.print(" WiFi.status(): "); Serial.print(WiFi.status()); Serial.print("\n"); - - // io.run(); is required for all sketches. - // it should always be present at the top of your loop - // function. it keeps the client connected to - // io.adafruit.com, and processes any incoming data. - // Here's where we check the network and start over if it has lost connection - Serial.print("Calling io.run()..."); // io.run() will hang if network disconnected 2019-11-16 - if(io.run() < AIO_NET_CONNECTED){ - Serial.print("No Network Connection!!! Reconnect!!!\n"); - count++; // count network restarts - setupIO(); // Start IO all over again - } - Serial.print("Done\n"); - - // save count to the 'counter' feed on Adafruit IO - Serial.print("sending -> "); - Serial.print(count); - if(counter->save(count)) Serial.print(" sent! (no proof of receipt)"); - else Serial.print(" failed to send!"); - - // Adafruit IO is rate limited for publishing, so a delay is required in - // between feed->save events. In this example, we will wait three seconds - // (1000 milliseconds == 1 second) during each loop. - // Adding the if statement allows you to generate a burst of faster saves - // to generate some throttling events and see how the code responds. - if(millis() < 90000 || millis() > 120000) delay(3000); - else delay(5000); - -} diff --git a/examples/adafruitio_02_pubsub_protected/config.h b/examples/adafruitio_02_pubsub_protected/config.h deleted file mode 100644 index 517161d3..00000000 --- a/examples/adafruitio_02_pubsub_protected/config.h +++ /dev/null @@ -1,67 +0,0 @@ -/************************ Adafruit IO Config *******************************/ - -// visit io.adafruit.com if you need to create an account, -// or if you need your Adafruit IO key. -// Uncomment these lines and add your own credentials if needed -//#define IO_USERNAME "your_username" -//#define IO_KEY "your_key" - -/******************************* WIFI **************************************/ - -// the AdafruitIO_WiFi client will work with the following boards: -// - HUZZAH ESP8266 Breakout -> https://www.adafruit.com/products/2471 -// - Feather HUZZAH ESP8266 -> https://www.adafruit.com/products/2821 -// - Feather HUZZAH ESP32 -> https://www.adafruit.com/product/3405 -// - Feather M0 WiFi -> https://www.adafruit.com/products/3010 -// - Feather WICED -> https://www.adafruit.com/products/3056 -// - Adafruit PyPortal -> https://www.adafruit.com/product/4116 -// - Adafruit Metro M4 Express AirLift Lite -> https://www.adafruit.com/product/4000 -// - Adafruit AirLift Breakout -> https://www.adafruit.com/product/4201 -// - Adafruit AirLift Shield -> https://www.adafruit.com/product/4285 -// - Adafruit AirLift FeatherWing -> https://www.adafruit.com/product/4264 - -//#define WIFI_SSID "your_ssid" -//#define WIFI_PASS "your_pass" - -// uncomment the following line if you are using airlift -// #define USE_AIRLIFT - -// uncomment the following line if you are using winc1500 -#define USE_WINC1500 - -// comment out the following lines if you are using fona or ethernet -#include "AdafruitIO_WiFi.h" - -#if defined(USE_AIRLIFT) || defined(ADAFRUIT_METRO_M4_AIRLIFT_LITE) - // Configure the pins used for the ESP32 connection - #if !defined(SPIWIFI_SS) // if the wifi definition isnt in the board variant - // Don't change the names of these #define's! they match the variant ones - #define SPIWIFI SPI - #define SPIWIFI_SS 10 // Chip select pin - #define NINA_ACK 9 // a.k.a BUSY or READY pin - #define NINA_RESETN 6 // Reset pin - #define NINA_GPIO0 -1 // Not connected - #endif - AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS, SPIWIFI_SS, NINA_ACK, NINA_RESETN, NINA_GPIO0, &SPIWIFI); -#else - AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS); -#endif -/******************************* FONA **************************************/ - -// the AdafruitIO_FONA client will work with the following boards: -// - Feather 32u4 FONA -> https://www.adafruit.com/product/3027 - -// uncomment the following two lines for 32u4 FONA, -// and comment out the AdafruitIO_WiFi client in the WIFI section -// #include "AdafruitIO_FONA.h" -// AdafruitIO_FONA io(IO_USERNAME, IO_KEY); - -/**************************** ETHERNET ************************************/ - -// the AdafruitIO_Ethernet client will work with the following boards: -// - Ethernet FeatherWing -> https://www.adafruit.com/products/3201 - -// uncomment the following two lines for ethernet, -// and comment out the AdafruitIO_WiFi client in the WIFI section -// #include "AdafruitIO_Ethernet.h" -// AdafruitIO_Ethernet io(IO_USERNAME, IO_KEY); From c071621a8c12baa0637493c031b4f15b47caf7a9 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Tue, 10 Dec 2019 14:00:26 -0500 Subject: [PATCH 14/15] Requested changes from pull request comments --- src/AdafruitIO.cpp | 17 +++++++---------- src/AdafruitIO.h | 4 ---- src/AdafruitIO_Definitions.h | 2 ++ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/AdafruitIO.cpp b/src/AdafruitIO.cpp index 37bb4fcb..a3710c25 100644 --- a/src/AdafruitIO.cpp +++ b/src/AdafruitIO.cpp @@ -168,18 +168,15 @@ const __FlashStringHelper* AdafruitIO::statusText() aio_status_t AdafruitIO::run(uint16_t busywait_ms) { uint32_t timeStart = millis(); - aio_status_t net_status = networkStatus(); - // If we aren't connected, return network status -- fail quickly - // Previous version would just hang on a network error - if(net_status != AIO_NET_CONNECTED) { - _status = net_status; - return _status; + // If we aren't network connected, return status -- fail quickly + if(status() < AIO_NET_CONNECTED) { + return status(); } // loop until we have a connection // mqttStatus() will try to reconnect before returning - while(mqttStatus() != AIO_CONNECTED && millis() - timeStart < ADAFRUITIO_RUN_TIMEOUT){} - if(mqttStatus() != AIO_CONNECTED) return _status; + while(mqttStatus() != AIO_CONNECTED && millis() - timeStart < AIO_MQTT_CONNECTION_TIMEOUT){} + if(mqttStatus() != AIO_CONNECTED) return status(); if(busywait_ms > 0) _packetread_timeout = busywait_ms; @@ -191,7 +188,7 @@ aio_status_t AdafruitIO::run(uint16_t busywait_ms) _mqtt->ping(); _last_ping = millis(); } - return _status; + return status(); } aio_status_t AdafruitIO::status() @@ -253,7 +250,7 @@ aio_status_t AdafruitIO::mqttStatus() if(_mqtt->connected()) return AIO_CONNECTED; - + switch(_mqtt->connect(_username, _key)) { case 0: return AIO_CONNECTED; diff --git a/src/AdafruitIO.h b/src/AdafruitIO.h index c6f2e72f..51facc5b 100644 --- a/src/AdafruitIO.h +++ b/src/AdafruitIO.h @@ -12,10 +12,6 @@ #ifndef ADAFRUITIO_H #define ADAFRUITIO_H -#ifndef ADAFRUITIO_RUN_TIMEOUT -#define ADAFRUITIO_RUN_TIMEOUT 60000 -#endif - #include "Arduino.h" #include "Adafruit_MQTT.h" #include "AdafruitIO_Definitions.h" diff --git a/src/AdafruitIO_Definitions.h b/src/AdafruitIO_Definitions.h index 646c7ee6..3ef5ef96 100644 --- a/src/AdafruitIO_Definitions.h +++ b/src/AdafruitIO_Definitions.h @@ -72,6 +72,8 @@ class AdafruitIOGroupCallback { #define AIO_PING_INTERVAL 60000 // Time to wait between re-connecting to Adafruit IO after throttled #define AIO_THROTTLE_RECONNECT_INTERVAL 60000 +// Time to wait for a successful reconnection of MQTT +#define AIO_MQTT_CONNECTION_TIMEOUT 60000 #define AIO_ERROR_TOPIC "/errors" #define AIO_THROTTLE_TOPIC "/throttle" From 3950f25135c895bf24f85f2da88a0d54df677bf2 Mon Sep 17 00:00:00 2001 From: Rick Sellens Date: Fri, 13 Dec 2019 18:27:30 -0500 Subject: [PATCH 15/15] Update library.properties to V3.3.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 9f3674ec..f194fa3b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit IO Arduino -version=3.2.3 +version=3.3.0 author=Adafruit maintainer=Adafruit sentence=Arduino library to access Adafruit IO.