Add connected() function to MQTT class. Update examples with robust reconnect logic.

This commit is contained in:
Tony DiCola 2015-07-05 14:29:13 -07:00
parent 207bcd44dd
commit 643c906aa6
7 changed files with 148 additions and 93 deletions

View File

@ -66,7 +66,7 @@
#define MQTT_CONN_KEEPALIVE 300
// Largest full packet we're able to send.
// Need to be able to store at least ~90 chars for a connect packet with full
// Need to be able to store at least ~90 chars for a connect packet with full
// 23 char client ID.
#define MAXBUFFERSIZE (105)
@ -92,7 +92,7 @@ class Adafruit_MQTT_Subscribe; // forward decl
class Adafruit_MQTT {
public:
Adafruit_MQTT(const char *server, uint16_t port, const char *cid,
Adafruit_MQTT(const char *server, uint16_t port, const char *cid,
const char *user, const char *pass);
virtual ~Adafruit_MQTT() {}
@ -111,10 +111,13 @@ class Adafruit_MQTT {
// otherwise.
virtual bool disconnect() = 0; // Subclasses need to fill this in!
// Return true if connected to the MQTT server, otherwise false.
virtual bool connected() = 0; // Subclasses need to fill this in!
// Publish a message to a topic using the specified QoS level. Returns true
// if the message was published, false otherwise.
bool publish(const char *topic, char *payload, uint8_t qos);
// Add a subscription to receive messages for a topic. Returns true if the
// subscription could be added, false otherwise.
bool subscribe(Adafruit_MQTT_Subscribe *sub);
@ -173,7 +176,7 @@ class Adafruit_MQTT_Publish {
// This might be ignored and a higher precision value sent.
bool publish(int32_t i);
bool publish(uint32_t i);
private:
Adafruit_MQTT *mqtt;
const char *topic;

View File

@ -28,7 +28,7 @@
// delay in ms between calls of available()
#define MQTT_CC3000_INTERAVAILDELAY 10
#define MQTT_CC3000_INTERAVAILDELAY 10
// CC3000-specific version of the Adafruit_MQTT class.
@ -37,7 +37,7 @@
// in the compilation of the library).
class Adafruit_MQTT_CC3000 : public Adafruit_MQTT {
public:
Adafruit_MQTT_CC3000(Adafruit_CC3000 *cc3k, const char *server, uint16_t port,
Adafruit_MQTT_CC3000(Adafruit_CC3000 *cc3k, const char *server, uint16_t port,
const char *cid, const char *user, const char *pass):
Adafruit_MQTT(server, port, cid, user, pass),
cc3000(cc3k)
@ -66,9 +66,9 @@ class Adafruit_MQTT_CC3000 : public Adafruit_MQTT {
if (!dnsretries) return false;
delay(500);
}
serverip = ip;
cc3000->printIPdotsRev(serverip);
cc3000->printIPdotsRev(serverip);
Serial.println();
}
@ -77,15 +77,24 @@ class Adafruit_MQTT_CC3000 : public Adafruit_MQTT {
// connect to server
DEBUG_PRINTLN(F("Connecting to TCP"));
mqttclient = cc3000->connectTCP(serverip, portnum);
return mqttclient.connected();
}
bool disconnect() {
return (mqttclient.close() == 0);
if (connected()) {
return (mqttclient.close() == 0);
}
else {
return true;
}
}
uint16_t readPacket(uint8_t *buffer, uint8_t maxlen, int16_t timeout,
bool connected() {
return mqttclient.connected();
}
uint16_t readPacket(uint8_t *buffer, uint8_t maxlen, int16_t timeout,
bool checkForValidPubPacket = false) {
/* Read data until either the connection is closed, or the idle timeout is reached. */
uint16_t len = 0;
@ -137,7 +146,7 @@ class Adafruit_MQTT_CC3000 : public Adafruit_MQTT {
}
return true;
}
private:
uint32_t serverip;
Adafruit_CC3000 *cc3000;

View File

@ -34,13 +34,21 @@ bool Adafruit_MQTT_Client::connectServer() {
}
bool Adafruit_MQTT_Client::disconnect() {
// Stop connection and return success (stop has no indication of failure).
client->stop();
return true;
// Stop connection if connected and return success (stop has no indication of
// failure).
if (client->connected()) {
client->stop();
}
return true;
}
bool Adafruit_MQTT_Client::connected() {
// Return true if connected, false if not connected.
return client->connected();
}
uint16_t Adafruit_MQTT_Client::readPacket(uint8_t *buffer, uint8_t maxlen,
int16_t timeout,
int16_t timeout,
bool checkForValidPubPacket) {
/* Read data until either the connection is closed, or the idle timeout is reached. */
uint16_t len = 0;

View File

@ -27,7 +27,7 @@
// How long to delay waiting for new data to be available in readPacket.
#define MQTT_CLIENT_READINTERVAL_MS 10
#define MQTT_CLIENT_READINTERVAL_MS 10
// MQTT client implementation for a generic Arduino Client interface. Can work
@ -44,10 +44,11 @@ class Adafruit_MQTT_Client : public Adafruit_MQTT {
bool connectServer();
bool disconnect();
uint16_t readPacket(uint8_t *buffer, uint8_t maxlen, int16_t timeout,
bool connected();
uint16_t readPacket(uint8_t *buffer, uint8_t maxlen, int16_t timeout,
bool checkForValidPubPacket = false);
bool sendPacket(uint8_t *buffer, uint8_t len);
private:
Client* client;
};

View File

@ -35,7 +35,7 @@
// in the compilation of the library).
class Adafruit_MQTT_FONA : public Adafruit_MQTT {
public:
Adafruit_MQTT_FONA(Adafruit_FONA *f, const char *server, uint16_t port,
Adafruit_MQTT_FONA(Adafruit_FONA *f, const char *server, uint16_t port,
const char *cid, const char *user, const char *pass):
Adafruit_MQTT(server, port, cid, user, pass),
fona(f)
@ -55,7 +55,12 @@ class Adafruit_MQTT_FONA : public Adafruit_MQTT {
return fona->TCPclose();
}
uint16_t readPacket(uint8_t *buffer, uint8_t maxlen, int16_t timeout,
bool connected() {
// Return true if connected, false if not connected.
return fona->TCPconnected();
}
uint16_t readPacket(uint8_t *buffer, uint8_t maxlen, int16_t timeout,
bool checkForValidPubPacket = false) {
uint8_t *buffp = buffer;
DEBUG_PRINTLN(F("Reading a packet.."));
@ -72,7 +77,7 @@ class Adafruit_MQTT_FONA : public Adafruit_MQTT {
DEBUG_PRINT('.');
while (avail = fona->TCPavailable()) {
DEBUG_PRINT('!');
if (len + avail > maxlen) {
avail = maxlen - len;
if (avail == 0) return len;
@ -80,7 +85,7 @@ class Adafruit_MQTT_FONA : public Adafruit_MQTT {
// try to read the data into the end of the pointer
if (! fona->TCPread(buffp, avail)) return len;
// read it! advance pointer
buffp += avail;
len += avail;
@ -103,14 +108,14 @@ class Adafruit_MQTT_FONA : public Adafruit_MQTT {
return len;
}
}
}
Watchdog.reset();
timeout -= MQTT_FONA_INTERAVAILDELAY;
timeout -= MQTT_FONA_QUERYDELAY; // this is how long it takes to query the FONA for avail()
delay(MQTT_FONA_INTERAVAILDELAY);
}
return len;
}
@ -127,9 +132,9 @@ class Adafruit_MQTT_FONA : public Adafruit_MQTT {
DEBUG_PRINTLN(F("Connection failed!"));
return false;
}
return true;
return true;
}
private:
uint32_t serverip;
Adafruit_FONA *fona;

View File

@ -1,14 +1,14 @@
/***************************************************
/***************************************************
Adafruit MQTT Library CC3000 Example
Designed specifically to work with the Adafruit WiFi products:
----> https://www.adafruit.com/products/1469
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_SleepyDog.h>
@ -30,7 +30,7 @@
#define WLAN_SSID "...your SSID..." // can't be longer than 32 characters!
#define WLAN_PASS "...your password..."
#define WLAN_SECURITY WLAN_SEC_WPA2 // Can be: WLAN_SEC_UNSEC, WLAN_SEC_WEP,
#define WLAN_SECURITY WLAN_SEC_WPA2 // Can be: WLAN_SEC_UNSEC, WLAN_SEC_WEP,
// WLAN_SEC_WPA or WLAN_SEC_WPA2
/************************* Adafruit.io Setup *********************************/
@ -64,12 +64,12 @@ boolean CC3000connect(const char* wlan_ssid, const char* wlan_pass, uint8_t wlan
/****************************** Feeds ***************************************/
// Setup a feed called 'photocell' for publishing.
// Setup a feed called 'photocell' for publishing.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
const char PHOTOCELL_FEED[] PROGMEM = AIO_USERNAME "/feeds/photocell";
Adafruit_MQTT_Publish photocell = Adafruit_MQTT_Publish(&mqtt, PHOTOCELL_FEED);
// Setup a feed called 'onoff' for subscribing to changes.
// Setup a feed called 'onoff' for subscribing to changes.
const char ONOFF_FEED[] PROGMEM = AIO_USERNAME "/feeds/onoff";
Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, ONOFF_FEED);
@ -84,7 +84,7 @@ void setup() {
// Initialise the CC3000 module
Serial.print(F("\nInit the CC3000..."));
if (!cc3000.begin())
if (!cc3000.begin())
halt("Failed");
mqtt.subscribe(&onoffbutton);
@ -93,31 +93,6 @@ void setup() {
Serial.println(F("Retrying WiFi"));
while(1);
}
Serial.println(F("Connected to WiFi!"));
//////////////////////////////
Serial.println(F("Connecting to MQTT..."));
int8_t ret;
while ((ret = mqtt.connect()) != 0) {
switch (ret) {
case 1: Serial.println(F("Wrong protocol")); break;
case 2: Serial.println(F("ID rejected")); break;
case 3: Serial.println(F("Server unavail")); break;
case 4: Serial.println(F("Bad user/pass")); break;
case 5: Serial.println(F("Not authed")); break;
case 6: Serial.println(F("Failed to subscribe")); break;
default: {
Serial.println(F("Connection failed"));
CC3000connect(WLAN_SSID, WLAN_PASS, WLAN_SECURITY); // y0w, lets connect to wifi again
return; // restart the loop
}
}
Serial.println(F("Retrying MQTT connection"));
delay(5000);
}
//////////////////////////////
Serial.println(F("MQTT Connected!"));
}
uint32_t x=0;
@ -125,6 +100,11 @@ uint32_t x=0;
void loop() {
// Make sure to reset watchdog every loop iteration!
Watchdog.reset();
// Ensure the connection to the MQTT server is alive (this will make the first
// connection and automatically reconnect when disconnected). See the MQTT_connect
// function definition further below.
MQTT_connect();
// Try to ping the MQTT server
/*
@ -140,13 +120,13 @@ void loop() {
Adafruit_MQTT_Subscribe *subscription;
while (subscription = mqtt.readSubscription(1000)) {
if (subscription == &onoffbutton) {
Serial.print(F("Got: "));
Serial.print(F("Got: "));
Serial.println((char *)onoffbutton.lastread);
}
}
// Now we can publish stuff!
Serial.print(F("\nSending photocell val "));
Serial.print(F("\nSending photocell val "));
Serial.print(x);
Serial.print("...");
if (! photocell.publish(x++)) {
@ -155,3 +135,35 @@ void loop() {
Serial.println(F("OK!"));
}
}
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
int8_t ret;
// Stop if already connected.
if (mqtt.connected()) {
return;
}
Serial.print("Connecting to MQTT... ");
while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
switch (ret) {
case 1: Serial.println("Wrong protocol"); break;
case 2: Serial.println("ID rejected"); break;
case 3: Serial.println("Server unavailable"); break;
case 4: Serial.println("Bad user/password"); break;
case 5: Serial.println("Not authenticated"); break;
case 6: Serial.println("Failed to subscribe"); break;
default:
Serial.println(F("Connection failed"));
CC3000connect(WLAN_SSID, WLAN_PASS, WLAN_SECURITY); // y0w, lets connect to wifi again
break;
}
Serial.println("Retrying MQTT connection in 5 seconds...");
mqtt.disconnect();
delay(5000); // wait 5 seconds
}
Serial.println("MQTT Connected!");
}

View File

@ -1,4 +1,4 @@
/***************************************************
/***************************************************
Adafruit MQTT Library ESP8266 Example
Must use ESP8266 Arduino from:
@ -7,11 +7,11 @@
Works great with Adafruit's Huzzah ESP board:
----> https://www.adafruit.com/product/2471
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Tony DiCola for Adafruit Industries.
Written by Tony DiCola for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <ESP8266WiFi.h>
@ -47,12 +47,12 @@ Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_CLIENTID, M
/****************************** Feeds ***************************************/
// Setup a feed called 'photocell' for publishing.
// Setup a feed called 'photocell' for publishing.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
const char PHOTOCELL_FEED[] PROGMEM = AIO_USERNAME "/feeds/photocell";
Adafruit_MQTT_Publish photocell = Adafruit_MQTT_Publish(&mqtt, PHOTOCELL_FEED);
// Setup a feed called 'onoff' for subscribing to changes.
// Setup a feed called 'onoff' for subscribing to changes.
const char ONOFF_FEED[] PROGMEM = AIO_USERNAME "/feeds/onoff";
Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, ONOFF_FEED);
@ -68,7 +68,7 @@ void setup() {
Serial.println(); Serial.println();
Serial.print("Connecting to ");
Serial.println(WLAN_SSID);
WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
@ -76,35 +76,21 @@ void setup() {
}
Serial.println();
Serial.println("WiFi connected");
Serial.println("WiFi connected");
Serial.println("IP address: "); Serial.println(WiFi.localIP());
// Setup MQTT subscription for onoff feed.
mqtt.subscribe(&onoffbutton);
// Connect to MQTT server.
Serial.println(F("Connecting to MQTT..."));
int8_t ret;
while ((ret = mqtt.connect()) != 0) {
switch (ret) {
case 1: Serial.println(F("Wrong protocol")); break;
case 2: Serial.println(F("ID rejected")); break;
case 3: Serial.println(F("Server unavail")); break;
case 4: Serial.println(F("Bad user/pass")); break;
case 5: Serial.println(F("Not authed")); break;
case 6: Serial.println(F("Failed to subscribe")); break;
default: Serial.println(F("Couldn't connect to MQTT server")); break;
}
Serial.println(F("Retrying MQTT connection"));
mqtt.disconnect();
delay(5000);
}
Serial.println(F("MQTT Connected!"));
}
uint32_t x=0;
void loop() {
// Ensure the connection to the MQTT server is alive (this will make the first
// connection and automatically reconnect when disconnected). See the MQTT_connect
// function definition further below.
MQTT_connect();
// Try to ping the MQTT server
/*
if (! mqtt.ping(3) ) {
@ -117,13 +103,13 @@ void loop() {
Adafruit_MQTT_Subscribe *subscription;
while (subscription = mqtt.readSubscription(1000)) {
if (subscription == &onoffbutton) {
Serial.print(F("Got: "));
Serial.print(F("Got: "));
Serial.println((char *)onoffbutton.lastread);
}
}
// Now we can publish stuff!
Serial.print(F("\nSending photocell val "));
Serial.print(F("\nSending photocell val "));
Serial.print(x);
Serial.print("...");
if (! photocell.publish(x++)) {
@ -134,3 +120,34 @@ void loop() {
delay(1000);
}
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
int8_t ret;
// Stop if already connected.
if (mqtt.connected()) {
return;
}
Serial.print("Connecting to MQTT... ");
while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
switch (ret) {
case 1: Serial.println("Wrong protocol"); break;
case 2: Serial.println("ID rejected"); break;
case 3: Serial.println("Server unavailable"); break;
case 4: Serial.println("Bad user/password"); break;
case 5: Serial.println("Not authenticated"); break;
case 6: Serial.println("Failed to subscribe"); break;
default: Serial.print("Couldn't connect to server, code: ");
Serial.println(ret);
break;
}
Serial.println("Retrying MQTT connection in 5 seconds...");
mqtt.disconnect();
delay(5000); // wait 5 seconds
}
Serial.println("MQTT Connected!");
}