From a0520d3265814b34ccbbdd897f41f5fcee3d633e Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Thu, 1 Oct 2015 12:00:56 -0400 Subject: [PATCH 01/29] default to MQTT_PROTOCOL_LEVEL 4 --- Adafruit_MQTT.cpp | 6 +++--- Adafruit_MQTT.h | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 5558a65..5a9c5f2 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -119,13 +119,13 @@ int8_t Adafruit_MQTT::connect() { // Connect to the server. if (!connectServer()) return -1; - + // Construct and send connect packet. uint8_t len = connectPacket(buffer); if (!sendPacket(buffer, len)) return -1; - // Read connect response packet and verify it + // Read connect response packet and verify it len = readPacket(buffer, 4, CONNECT_TIMEOUT_MS); if (len != 4) return -1; @@ -143,7 +143,7 @@ int8_t Adafruit_MQTT::connect() { uint8_t len = subscribePacket(buffer, subscriptions[i]->topic, subscriptions[i]->qos); if (!sendPacket(buffer, len)) return -1; - + // Get SUBACK len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS); DEBUG_PRINT(F("SUBACK:\t")); diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index e18110e..f093254 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -29,7 +29,7 @@ #endif // Uncomment/comment to turn on/off debug output messages. -//#define MQTT_DEBUG +#define MQTT_DEBUG // Set where debug messages will be printed. #define DEBUG_PRINTER Serial @@ -45,7 +45,9 @@ #define DEBUG_PRINTBUFFER(buffer, len) {} #endif -#define MQTT_PROTOCOL_LEVEL 3 +#ifndef MQTT_PROTOCOL_LEVEL + #define MQTT_PROTOCOL_LEVEL 4 +#endif #define MQTT_CTRL_CONNECT 0x01 #define MQTT_CTRL_CONNECTACK 0x02 From ea779b1daaf26daa84e96e0a071d6cc2a9eb46c7 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Fri, 2 Oct 2015 10:43:11 -0400 Subject: [PATCH 02/29] allow user to define MQTT KEEPALIVE in sketch --- Adafruit_MQTT.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index f093254..b9a4c4a 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -65,7 +65,9 @@ #define PING_TIMEOUT_MS 500 // Adjust as necessary, in seconds. Default to 5 minutes. -#define MQTT_CONN_KEEPALIVE 300 +#ifndef MQTT_CONN_KEEPALIVE + #define MQTT_CONN_KEEPALIVE 300 +#endif // Largest full packet we're able to send. // Need to be able to store at least ~90 chars for a connect packet with full From a3925bdb6ba42c287d5e60110a6938b4eda5adbd Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Fri, 2 Oct 2015 10:45:00 -0400 Subject: [PATCH 03/29] adds MQTT 3.1.1 connect packet changes --- Adafruit_MQTT.cpp | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 5a9c5f2..261e464 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -26,7 +26,7 @@ void printBuffer(uint8_t *buffer, uint8_t len) { for (uint8_t i=0; i 0) { len = readPacket(buffer, 4, PUBLISH_TIMEOUT_MS); @@ -262,11 +243,11 @@ bool Adafruit_MQTT::ping(uint8_t times) { uint8_t len = pingPacket(buffer); if (!sendPacket(buffer, len)) return false; - + // Process ping reply. len = readPacket(buffer, 2, PING_TIMEOUT_MS); if (buffer[0] == (MQTT_CTRL_PINGRESP << 4)) - return true; + return true; } return false; } @@ -287,7 +268,10 @@ uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) { p+=2; // fill in packet[1] last - p = stringprint_P(p, PSTR("MQIsdp")); + if(MQTT_PROTOCOL_LEVEL == 3) + p = stringprint_P(p, PSTR("MQIsdp")); + else + p = stringprint_P(p, PSTR("MQTT")); p[0] = MQTT_PROTOCOL_LEVEL; p++; @@ -305,7 +289,13 @@ uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) { p[0] = MQTT_CONN_KEEPALIVE & 0xFF; p++; - p = stringprint_P(p, clientid, 23); // Limit client ID to first 23 characters. + if(MQTT_PROTOCOL_LEVEL == 3) { + p = stringprint_P(p, clientid, 23); // Limit client ID to first 23 characters. + } else { + if (pgm_read_byte(clientid) != 0) { + p = stringprint_P(p, clientid); + } + } if (pgm_read_byte(username) != 0) { p = stringprint_P(p, username); From 913cce41af99e306f2fcaf25fcada5ca49e82c19 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Fri, 2 Oct 2015 17:10:16 -0400 Subject: [PATCH 04/29] adds zero byte client id option for 3.1.1 --- Adafruit_MQTT.cpp | 6 ++++++ Adafruit_MQTT.h | 8 ++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 261e464..f038ec9 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -294,6 +294,12 @@ uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) { } else { if (pgm_read_byte(clientid) != 0) { p = stringprint_P(p, clientid); + } else { + p[0] = 0x0; + p++; + p[0] = 0x0; + p++; + DEBUG_PRINTLN(F("SERVER GENERATING CLIENT ID")); } } diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index b9a4c4a..c0f68f1 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -45,9 +45,7 @@ #define DEBUG_PRINTBUFFER(buffer, len) {} #endif -#ifndef MQTT_PROTOCOL_LEVEL - #define MQTT_PROTOCOL_LEVEL 4 -#endif +#define MQTT_PROTOCOL_LEVEL 4 #define MQTT_CTRL_CONNECT 0x01 #define MQTT_CTRL_CONNECTACK 0x02 @@ -65,9 +63,7 @@ #define PING_TIMEOUT_MS 500 // Adjust as necessary, in seconds. Default to 5 minutes. -#ifndef MQTT_CONN_KEEPALIVE - #define MQTT_CONN_KEEPALIVE 300 -#endif +#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 From 4f3466bdbf505ac9918c33be98f41cf182ac9fe3 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Fri, 2 Oct 2015 17:13:35 -0400 Subject: [PATCH 05/29] comment out MQTT_DEBUG --- Adafruit_MQTT.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index c0f68f1..34a39d6 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -29,7 +29,7 @@ #endif // Uncomment/comment to turn on/off debug output messages. -#define MQTT_DEBUG +//#define MQTT_DEBUG // Set where debug messages will be printed. #define DEBUG_PRINTER Serial From dfbe6a1e11e8e9cfb4b856a1c0b1d2a514b7863e Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Fri, 2 Oct 2015 17:22:31 -0400 Subject: [PATCH 06/29] remove client id from esp example --- examples/mqtt_esp8266/mqtt_esp8266.ino | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index 8f06265..ca72c59 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -38,15 +38,11 @@ WiFiClient client; // Store the MQTT server, client ID, username, and password in flash memory. // This is required for using the Adafruit MQTT library. const char MQTT_SERVER[] PROGMEM = AIO_SERVER; -// Set a unique MQTT client ID using the AIO key + the date and time the sketch -// was compiled (so this should be unique across multiple devices for a user, -// alternatively you can manually set this to a GUID or other random value). -const char MQTT_CLIENTID[] PROGMEM = __TIME__ AIO_USERNAME; const char MQTT_USERNAME[] PROGMEM = AIO_USERNAME; const char MQTT_PASSWORD[] PROGMEM = AIO_KEY; // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. -Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_CLIENTID, MQTT_USERNAME, MQTT_PASSWORD); +Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, "", MQTT_USERNAME, MQTT_PASSWORD); /****************************** Feeds ***************************************/ From 78d733aee359d4d93cf74af7d8a4e21709a59723 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 09:14:17 -0400 Subject: [PATCH 07/29] define the missing MQTT control packets --- Adafruit_MQTT.h | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 34a39d6..32b7816 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -47,20 +47,27 @@ #define MQTT_PROTOCOL_LEVEL 4 -#define MQTT_CTRL_CONNECT 0x01 -#define MQTT_CTRL_CONNECTACK 0x02 -#define MQTT_CTRL_PUBLISH 0x03 -#define MQTT_CTRL_SUBSCRIBE 0x08 -#define MQTT_CTRL_SUBACK 0x09 -#define MQTT_CTRL_PINGREQ 0x0C -#define MQTT_CTRL_PINGRESP 0x0D +#define MQTT_CTRL_CONNECT 0x1 +#define MQTT_CTRL_CONNECTACK 0x2 +#define MQTT_CTRL_PUBLISH 0x3 +#define MQTT_CTRL_PUBACK 0x4 +#define MQTT_CTRL_PUBREC 0x5 +#define MQTT_CTRL_PUBREL 0x6 +#define MQTT_CTRL_PUBCOMP 0x7 +#define MQTT_CTRL_SUBSCRIBE 0x8 +#define MQTT_CTRL_SUBACK 0x9 +#define MQTT_CTRL_UNSUBSCRIBE 0xA +#define MQTT_CTRL_UNSUBSACK 0xB +#define MQTT_CTRL_PINGREQ 0xC +#define MQTT_CTRL_PINGRESP 0xD +#define MQTT_CTRL_DISCONNECT 0xE #define MQTT_QOS_1 0x1 #define MQTT_QOS_0 0x0 #define CONNECT_TIMEOUT_MS 3000 #define PUBLISH_TIMEOUT_MS 500 -#define PING_TIMEOUT_MS 500 +#define PING_TIMEOUT_MS 500 // Adjust as necessary, in seconds. Default to 5 minutes. #define MQTT_CONN_KEEPALIVE 300 @@ -70,15 +77,15 @@ // 23 char client ID. #define MAXBUFFERSIZE (125) -#define MQTT_CONN_USERNAMEFLAG 0x80 -#define MQTT_CONN_PASSWORDFLAG 0x40 -#define MQTT_CONN_WILLRETAIN 0x20 -#define MQTT_CONN_WILLQOS 0x08 -#define MQTT_CONN_WILLFLAG 0x04 -#define MQTT_CONN_CLEANSESSION 0x02 +#define MQTT_CONN_USERNAMEFLAG 0x80 +#define MQTT_CONN_PASSWORDFLAG 0x40 +#define MQTT_CONN_WILLRETAIN 0x20 +#define MQTT_CONN_WILLQOS_1 0x08 +#define MQTT_CONN_WILLQOS_2 0x18 +#define MQTT_CONN_WILLFLAG 0x04 +#define MQTT_CONN_CLEANSESSION 0x02 -// how many subscriptions we want to be able to -// track +// how many subscriptions we want to be able to track #define MAXSUBSCRIPTIONS 5 // how much data we save in a subscription object From b9a04c8be5873c94493efebe3814f3354eb3bea3 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 09:25:07 -0400 Subject: [PATCH 08/29] adds will() method def --- Adafruit_MQTT.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 32b7816..14940af 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -131,6 +131,14 @@ class Adafruit_MQTT { // Return true if connected to the MQTT server, otherwise false. virtual bool connected() = 0; // Subclasses need to fill this in! + // Set MQTT last will topic, payload, QOS, and retain. This needs + // to be called before connect() because it is sent as part of the + // connect control packet. + bool will(const char *topic, const char *payload, uint8_t qos = 0, uint8_t retain = 0); + bool will(const __FlashStringHelper *topic, const char *payload, uint8_t qos = 0, uint8_t retain = 0) { + return will((const char *)topic, payload, qos, retain); + } + // Publish a message to a topic using the specified QoS level. Returns true // if the message was published, false otherwise. // The topic must be stored in PROGMEM. It can either be a From b2a198af5a67feb85f9a354e880ba5f748e0b149 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 09:26:06 -0400 Subject: [PATCH 09/29] adds unsubscribe() method def --- Adafruit_MQTT.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 14940af..1fbd755 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -154,6 +154,9 @@ class Adafruit_MQTT { // is made is not currently supported. bool subscribe(Adafruit_MQTT_Subscribe *sub); + // Unsubscribe from a previously subscribed MQTT topic. + bool unsubscribe(Adafruit_MQTT_Subscribe *sub); + // Check if any subscriptions have new messages. Will return a reference to // an Adafruit_MQTT_Subscribe object which has a new message. Should be called // in the sketch's loop function to ensure new messages are recevied. Note From e60be3e972a9e54844e355007f47e96c47164689 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 09:27:31 -0400 Subject: [PATCH 10/29] adds unsubscribePacket method def --- Adafruit_MQTT.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 1fbd755..e567d47 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -198,6 +198,7 @@ class Adafruit_MQTT { uint8_t connectPacket(uint8_t *packet); uint8_t publishPacket(uint8_t *packet, const char *topic, const char *payload, uint8_t qos); uint8_t subscribePacket(uint8_t *packet, const char *topic, uint8_t qos); + uint8_t unsubscribePacket(uint8_t *packet, const char *topic); uint8_t pingPacket(uint8_t *packet); }; From e9e154ab52e45035df37fc445bae08492bf534aa Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 09:45:27 -0400 Subject: [PATCH 11/29] adds will support to the connect packet --- Adafruit_MQTT.cpp | 18 +++++++++++++++++- Adafruit_MQTT.h | 4 ++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index f038ec9..3f12f39 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -276,13 +276,29 @@ uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) { p[0] = MQTT_PROTOCOL_LEVEL; p++; + // always clean the session p[0] = MQTT_CONN_CLEANSESSION; + + // set the will flags if needed + if (pgm_read_byte(will_topic) != 0) { + + p[0] |= MQTT_CONN_WILLFLAG; + + if(will_qos == 1) + p[0] |= MQTT_CONN_WILLQOS_1; + else if(will_qos == 2) + p[0] |= MQTT_CONN_WILLQOS_2; + + if(will_retain == 1) + p[0] |= MQTT_CONN_WILLRETAIN; + + } + if (pgm_read_byte(username) != 0) p[0] |= MQTT_CONN_USERNAMEFLAG; if (pgm_read_byte(password) != 0) p[0] |= MQTT_CONN_PASSWORDFLAG; p++; - // TODO: add WILL support? p[0] = MQTT_CONN_KEEPALIVE >> 8; p++; diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index e567d47..29e4e70 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -189,6 +189,10 @@ class Adafruit_MQTT { const char *clientid; const char *username; const char *password; + const char *will_topic; + const char *will_payload; + uint8_t will_qos; + uint8_t will_retain; uint8_t buffer[MAXBUFFERSIZE]; // one buffer, used for all incoming/outgoing private: From 476d1115e67e1b7232adcac9cde05c9b6e5ccebe Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 09:50:57 -0400 Subject: [PATCH 12/29] adds will() function --- Adafruit_MQTT.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 3f12f39..de046f0 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -167,6 +167,22 @@ bool Adafruit_MQTT::publish(const char *topic, const char *data, uint8_t qos) { return true; } +bool Adafruit_MQTT::will(const char *topic, const char *payload, uint8_t qos, uint8_t retain) { + + if (connected()) { + DEBUG_PRINT(F("Will defined after connect")); + return false; + } + + will_topic = topic; + will_payload = payload; + will_qos = qos; + will_retain = retain; + + return true; + +} + bool Adafruit_MQTT::subscribe(Adafruit_MQTT_Subscribe *sub) { uint8_t i; // see if we are already subscribed From 0fbd7346466ce3bab9400e7cba529b1420e4a617 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 10:33:33 -0400 Subject: [PATCH 13/29] adds unsubscribe & unsubscribePacket functions --- Adafruit_MQTT.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++ Adafruit_MQTT.h | 2 +- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index de046f0..6d5a45a 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -206,6 +206,50 @@ bool Adafruit_MQTT::subscribe(Adafruit_MQTT_Subscribe *sub) { return false; } +bool Adafruit_MQTT::unsubscribe(Adafruit_MQTT_Subscribe *sub) { + uint8_t i; + + // see if we are already subscribed + for (i=0; itopic); + + // sending unsubscribe failed + if (! sendPacket(buffer, len)) + return false; + + // if QoS for this subscription is 1 or 2, we need + // to wait for the unsuback to confirm unsubscription + if(subscriptions[i]->qos > 0) { + + // wait for UNSUBACK + len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS); + DEBUG_PRINT(F("UNSUBACK:\t")); + DEBUG_PRINTBUFFER(buffer, len); + + if ((len != 5) || (buffer[0] != (MQTT_CTRL_UNSUBACK << 4))) { + return false; // failure to unsubscribe + } + + } + + subscriptions[i] = 0; + return true; + + } + + } + + // subscription not found, so we are unsubscribed + return true; + +} + Adafruit_MQTT_Subscribe *Adafruit_MQTT::readSubscription(int16_t timeout) { uint8_t i, topiclen, datalen; @@ -396,6 +440,31 @@ uint8_t Adafruit_MQTT::subscribePacket(uint8_t *packet, const char *topic, return len; } +uint8_t Adafruit_MQTT::unsubscribePacket(uint8_t *packet, const char *topic) { + + uint8_t *p = packet; + uint16_t len; + + p[0] = MQTT_CTRL_UNSUBSCRIBE << 4 | 0x1; + // fill in packet[1] last + p+=2; + + // packet identifier. used for QoS > 1 + // TODO: this shouldn't be a static value + p[0] = 0xAD; + p[1] = 0xAF; + p+=2; + + p = stringprint_P(p, topic); + + len = p - packet; + packet[1] = len-2; // don't include the 2 bytes of fixed header data + DEBUG_PRINTLN(F("MQTT unsubscription packet:")); + DEBUG_PRINTBUFFER(buffer, len); + return len; + +} + uint8_t Adafruit_MQTT::pingPacket(uint8_t *packet) { packet[0] = MQTT_CTRL_PINGREQ << 4; packet[1] = 0; diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 29e4e70..ad5653d 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -57,7 +57,7 @@ #define MQTT_CTRL_SUBSCRIBE 0x8 #define MQTT_CTRL_SUBACK 0x9 #define MQTT_CTRL_UNSUBSCRIBE 0xA -#define MQTT_CTRL_UNSUBSACK 0xB +#define MQTT_CTRL_UNSUBACK 0xB #define MQTT_CTRL_PINGREQ 0xC #define MQTT_CTRL_PINGRESP 0xD #define MQTT_CTRL_DISCONNECT 0xE From 765a2feaffb26f6e12ee63bc50da7d075e1ec76e Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 10:38:09 -0400 Subject: [PATCH 14/29] remove broken while loop from ping() --- Adafruit_MQTT.cpp | 23 ++++++++++++----------- Adafruit_MQTT.h | 5 ++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 6d5a45a..7f4f587 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -297,19 +297,20 @@ Adafruit_MQTT_Subscribe *Adafruit_MQTT::readSubscription(int16_t timeout) { return subscriptions[i]; } -bool Adafruit_MQTT::ping(uint8_t times) { - while (times) { - // Construct and send ping packet. - uint8_t len = pingPacket(buffer); - if (!sendPacket(buffer, len)) - return false; +bool Adafruit_MQTT::ping() { + + // Construct and send ping packet. + uint8_t len = pingPacket(buffer); + if (!sendPacket(buffer, len)) + return false; + + // Process ping reply. + len = readPacket(buffer, 2, PING_TIMEOUT_MS); + if (buffer[0] == (MQTT_CTRL_PINGRESP << 4)) + return true; - // Process ping reply. - len = readPacket(buffer, 2, PING_TIMEOUT_MS); - if (buffer[0] == (MQTT_CTRL_PINGRESP << 4)) - return true; - } return false; + } // Packet Generation Functions ///////////////////////////////////////////////// diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index ad5653d..5a9965d 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -163,9 +163,8 @@ class Adafruit_MQTT { // that subscribe should be called first for each topic that receives messages! Adafruit_MQTT_Subscribe *readSubscription(int16_t timeout=0); - // Ping the server to ensure the connection is still alive. Returns true if - // successful, otherwise false. - bool ping(uint8_t t); + // Ping the server to ensure the connection is still alive. + bool ping(); protected: // Interface that subclasses need to implement: From b9c9a288836c24937462afa371147474b5f50e78 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 11:21:05 -0400 Subject: [PATCH 15/29] adds packet ids for publish QoS > 0 also adds packet id counter so packet ids aren't static values. this is a step in the direction of QoS 1 support --- Adafruit_MQTT.cpp | 31 +++++++++++++++++++++++-------- Adafruit_MQTT.h | 1 + 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 7f4f587..d7e6fe1 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -225,7 +225,7 @@ bool Adafruit_MQTT::unsubscribe(Adafruit_MQTT_Subscribe *sub) { // if QoS for this subscription is 1 or 2, we need // to wait for the unsuback to confirm unsubscription - if(subscriptions[i]->qos > 0) { + if(subscriptions[i]->qos > 0 && MQTT_PROTOCOL_LEVEL > 3) { // wait for UNSUBACK len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS); @@ -404,6 +404,16 @@ uint8_t Adafruit_MQTT::publishPacket(uint8_t *packet, const char *topic, // fill in packet[1] last p+=2; + // add packet identifier. used for checking PUBACK in QOS > 0 + if(qos > 0) { + p[0] = (packet_id_counter >> 8) & 0xFF; + p[1] = packet_id_counter & 0xFF; + p+=2; + + // increment the packet id + packet_id_counter++; + } + p = stringprint_P(p, topic); memcpy(p, data, strlen(data)); @@ -424,11 +434,14 @@ uint8_t Adafruit_MQTT::subscribePacket(uint8_t *packet, const char *topic, // fill in packet[1] last p+=2; - // put in a message id, - p[0] = 0xAD; - p[1] = 0xAF; + // packet identifier. used for checking SUBACK + p[0] = (packet_id_counter >> 8) & 0xFF; + p[1] = packet_id_counter & 0xFF; p+=2; + // increment the packet id + packet_id_counter++; + p = stringprint_P(p, topic); p[0] = qos; @@ -450,12 +463,14 @@ uint8_t Adafruit_MQTT::unsubscribePacket(uint8_t *packet, const char *topic) { // fill in packet[1] last p+=2; - // packet identifier. used for QoS > 1 - // TODO: this shouldn't be a static value - p[0] = 0xAD; - p[1] = 0xAF; + // packet identifier. used for checking UNSUBACK + p[0] = (packet_id_counter >> 8) & 0xFF; + p[1] = packet_id_counter & 0xFF; p+=2; + // increment the packet id + packet_id_counter++; + p = stringprint_P(p, topic); len = p - packet; diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 5a9965d..0ddf925 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -193,6 +193,7 @@ class Adafruit_MQTT { uint8_t will_qos; uint8_t will_retain; uint8_t buffer[MAXBUFFERSIZE]; // one buffer, used for all incoming/outgoing + uint16_t packet_id_counter = 0; private: Adafruit_MQTT_Subscribe *subscriptions[MAXSUBSCRIPTIONS]; From e70e2367b6383173f3a9d91b7062ad9610f36759 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 11:32:10 -0400 Subject: [PATCH 16/29] only check for suback if using MQTT 3.1.1 or higher --- Adafruit_MQTT.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index d7e6fe1..302c47e 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -125,13 +125,16 @@ int8_t Adafruit_MQTT::connect() { if (!sendPacket(buffer, len)) return -1; - // Get SUBACK - len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS); - DEBUG_PRINT(F("SUBACK:\t")); - DEBUG_PRINTBUFFER(buffer, len); - if ((len != 5) || (buffer[0] != (MQTT_CTRL_SUBACK << 4))) { - return 6; // failure to subscribe + // Check for SUBACK if using MQTT 3.1.1 or higher + if(MQTT_PROTOCOL_LEVEL > 3) { + len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS); + DEBUG_PRINT(F("SUBACK:\t")); + DEBUG_PRINTBUFFER(buffer, len); + if ((len != 5) || (buffer[0] != (MQTT_CTRL_SUBACK << 4))) { + return 6; // failure to subscribe + } } + } return 0; From 921c132f92f2879a0c9400d73293255d2a6d50c8 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 13:41:14 -0400 Subject: [PATCH 17/29] adds missing will payload to connect packet --- Adafruit_MQTT.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 302c47e..e738472 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -126,6 +126,8 @@ int8_t Adafruit_MQTT::connect() { return -1; // Check for SUBACK if using MQTT 3.1.1 or higher + // TODO: The Server is permitted to start sending PUBLISH packets matching the + // Subscription before the Server sends the SUBACK Packet. if(MQTT_PROTOCOL_LEVEL > 3) { len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS); DEBUG_PRINT(F("SUBACK:\t")); @@ -344,7 +346,7 @@ uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) { p[0] = MQTT_CONN_CLEANSESSION; // set the will flags if needed - if (pgm_read_byte(will_topic) != 0) { + if (will_topic && pgm_read_byte(will_topic) != 0) { p[0] |= MQTT_CONN_WILLFLAG; @@ -383,6 +385,11 @@ uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) { } } + if (will_topic && pgm_read_byte(will_topic) != 0) { + p = stringprint_P(p, will_topic); + p = stringprint_P(p, will_payload); + } + if (pgm_read_byte(username) != 0) { p = stringprint_P(p, username); } From f9ae6f31462fc61f1ca2d3d2571c9d6c899be6c8 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 13:46:38 -0400 Subject: [PATCH 18/29] comment out suback for now --- Adafruit_MQTT.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index e738472..fc52516 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -128,14 +128,14 @@ int8_t Adafruit_MQTT::connect() { // Check for SUBACK if using MQTT 3.1.1 or higher // TODO: The Server is permitted to start sending PUBLISH packets matching the // Subscription before the Server sends the SUBACK Packet. - if(MQTT_PROTOCOL_LEVEL > 3) { - len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS); - DEBUG_PRINT(F("SUBACK:\t")); - DEBUG_PRINTBUFFER(buffer, len); - if ((len != 5) || (buffer[0] != (MQTT_CTRL_SUBACK << 4))) { - return 6; // failure to subscribe - } - } + // if(MQTT_PROTOCOL_LEVEL > 3) { + // len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS); + // DEBUG_PRINT(F("SUBACK:\t")); + // DEBUG_PRINTBUFFER(buffer, len); + // if ((len != 5) || (buffer[0] != (MQTT_CTRL_SUBACK << 4))) { + // return 6; // failure to subscribe + // } + // } } From 16da46aece9a45bdcb2065eebe0deff33c415747 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 14:07:49 -0400 Subject: [PATCH 19/29] renames disconnect to disconnectServer and adds disconnectPacket --- Adafruit_MQTT.cpp | 2 +- Adafruit_MQTT.h | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index fc52516..66bd2fa 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -279,7 +279,7 @@ Adafruit_MQTT_Subscribe *Adafruit_MQTT::readSubscription(int16_t timeout) { // to make comparison case insensitive. if (strncasecmp_P((char*)buffer+4, subscriptions[i]->topic, topiclen) == 0) { DEBUG_PRINT(F("Found sub #")); DEBUG_PRINTLN(i); - break; + break; } } } diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 0ddf925..de05d50 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -124,9 +124,8 @@ class Adafruit_MQTT { // Serial.println without any further processing. const __FlashStringHelper* connectErrorString(int8_t code); - // Disconnect from the MQTT server. Returns true if disconnected, false - // otherwise. - virtual bool disconnect() = 0; // Subclasses need to fill this in! + // Sends MQTT disconnect packet and calls disconnectServer() + bool disconnect(); // Return true if connected to the MQTT server, otherwise false. virtual bool connected() = 0; // Subclasses need to fill this in! @@ -172,6 +171,9 @@ class Adafruit_MQTT { // Connect to the server and return true if successful, false otherwise. virtual bool connectServer() = 0; + // Disconnect from the MQTT server. Returns true if disconnected, false otherwise. + virtual bool disconnectServer() = 0; // Subclasses need to fill this in! + // Send data to the server specified by the buffer and length of data. virtual bool sendPacket(uint8_t *buffer, uint8_t len) = 0; @@ -200,6 +202,7 @@ class Adafruit_MQTT { // Functions to generate MQTT packets. uint8_t connectPacket(uint8_t *packet); + uint8_t disconnectPacket(uint8_t *packet); uint8_t publishPacket(uint8_t *packet, const char *topic, const char *payload, uint8_t qos); uint8_t subscribePacket(uint8_t *packet, const char *topic, uint8_t qos); uint8_t unsubscribePacket(uint8_t *packet, const char *topic); From 4ab72be73e430439a71c87b8c9e19d675f85682f Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 14:18:31 -0400 Subject: [PATCH 20/29] adds disconnect & disconnectPacket functions --- Adafruit_MQTT.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 66bd2fa..79a1ffe 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -155,6 +155,18 @@ const __FlashStringHelper* Adafruit_MQTT::connectErrorString(int8_t code) { } } +bool Adafruit_MQTT::disconnect() { + + // Construct and send disconnect packet. + uint8_t len = disconnectPacket(buffer); + if (! sendPacket(buffer, len)) + DEBUG_PRINTLN(F("Unable to send disconnect packet")); + + return disconnectServer(); + +} + + bool Adafruit_MQTT::publish(const char *topic, const char *data, uint8_t qos) { // Construct and send publish packet. uint8_t len = publishPacket(buffer, topic, data, qos); @@ -499,6 +511,14 @@ uint8_t Adafruit_MQTT::pingPacket(uint8_t *packet) { return 2; } +uint8_t Adafruit_MQTT::disconnectPacket(uint8_t *packet) { + packet[0] = MQTT_CTRL_DISCONNECT << 4; + packet[1] = 0; + DEBUG_PRINTLN(F("MQTT disconnect packet:")); + DEBUG_PRINTBUFFER(buffer, 2); + return 2; +} + // Adafruit_MQTT_Publish Definition //////////////////////////////////////////// From aa6db4d5f51e92ad38f2c8541e70e45cd33fe593 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 14:18:49 -0400 Subject: [PATCH 21/29] rename all subclass diconnect() to disconnectServer() --- Adafruit_MQTT_CC3000.h | 2 +- Adafruit_MQTT_Client.cpp | 2 +- Adafruit_MQTT_Client.h | 2 +- Adafruit_MQTT_FONA.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Adafruit_MQTT_CC3000.h b/Adafruit_MQTT_CC3000.h index a1f6ea6..f064f0c 100644 --- a/Adafruit_MQTT_CC3000.h +++ b/Adafruit_MQTT_CC3000.h @@ -81,7 +81,7 @@ class Adafruit_MQTT_CC3000 : public Adafruit_MQTT { return mqttclient.connected(); } - bool disconnect() { + bool disconnectServer() { if (connected()) { return (mqttclient.close() == 0); } diff --git a/Adafruit_MQTT_Client.cpp b/Adafruit_MQTT_Client.cpp index e0686d9..6612c8f 100644 --- a/Adafruit_MQTT_Client.cpp +++ b/Adafruit_MQTT_Client.cpp @@ -33,7 +33,7 @@ bool Adafruit_MQTT_Client::connectServer() { return r != 0; } -bool Adafruit_MQTT_Client::disconnect() { +bool Adafruit_MQTT_Client::disconnectServer() { // Stop connection if connected and return success (stop has no indication of // failure). if (client->connected()) { diff --git a/Adafruit_MQTT_Client.h b/Adafruit_MQTT_Client.h index e78c81b..416aef2 100644 --- a/Adafruit_MQTT_Client.h +++ b/Adafruit_MQTT_Client.h @@ -43,7 +43,7 @@ class Adafruit_MQTT_Client : public Adafruit_MQTT { {} bool connectServer(); - bool disconnect(); + bool disconnectServer(); bool connected(); uint16_t readPacket(uint8_t *buffer, uint8_t maxlen, int16_t timeout, bool checkForValidPubPacket = false); diff --git a/Adafruit_MQTT_FONA.h b/Adafruit_MQTT_FONA.h index 17d73fe..204d10f 100644 --- a/Adafruit_MQTT_FONA.h +++ b/Adafruit_MQTT_FONA.h @@ -51,7 +51,7 @@ class Adafruit_MQTT_FONA : public Adafruit_MQTT { return fona->TCPconnect(server, portnum); } - bool disconnect() { + bool disconnectServer() { return fona->TCPclose(); } From b48265faedc40e3ac94a5d2f0563c8fe4ed14e58 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 14:54:37 -0400 Subject: [PATCH 22/29] support anon auth & generated client id in constructor --- Adafruit_MQTT.cpp | 18 +++++++++++++----- Adafruit_MQTT.h | 14 ++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 79a1ffe..8c461dd 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -70,30 +70,39 @@ static uint8_t *stringprint_P(uint8_t *p, const char *s, uint16_t maxlen=0) { // Adafruit_MQTT Definition //////////////////////////////////////////////////// -Adafruit_MQTT::Adafruit_MQTT(const char *server, uint16_t port, const char *cid, - const char *user, const char *pass) { +Adafruit_MQTT::Adafruit_MQTT(const char *server, uint16_t port, + const char *user, const char *pass, + const char *cid) { servername = server; portnum = port; clientid = cid; username = user; password = pass; + // reset subscriptions for (uint8_t i=0; i Date: Mon, 5 Oct 2015 14:57:44 -0400 Subject: [PATCH 23/29] rearrange child classes to match new constructor --- Adafruit_MQTT_CC3000.h | 10 +++++++--- Adafruit_MQTT_Client.h | 11 +++++++---- Adafruit_MQTT_FONA.h | 10 +++++++--- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Adafruit_MQTT_CC3000.h b/Adafruit_MQTT_CC3000.h index f064f0c..e7e8eba 100644 --- a/Adafruit_MQTT_CC3000.h +++ b/Adafruit_MQTT_CC3000.h @@ -37,9 +37,13 @@ // 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, - const char *cid, const char *user, const char *pass): - Adafruit_MQTT(server, port, cid, user, pass), + Adafruit_MQTT_CC3000(Adafruit_CC3000 *cc3k, + const char *server = "io.adafruit.com", + uint16_t port = 1883, + const char *user = "", + const char *pass = "", + const char *cid = ""): + Adafruit_MQTT(server, port, user, pass, cid), cc3000(cc3k) {} diff --git a/Adafruit_MQTT_Client.h b/Adafruit_MQTT_Client.h index 416aef2..20d704f 100644 --- a/Adafruit_MQTT_Client.h +++ b/Adafruit_MQTT_Client.h @@ -35,10 +35,13 @@ // and even other platforms like ESP8266. class Adafruit_MQTT_Client : public Adafruit_MQTT { public: - Adafruit_MQTT_Client(Client *client, const char *server, uint16_t port, - const char *cid, const char *user, - const char *pass): - Adafruit_MQTT(server, port, cid, user, pass), + Adafruit_MQTT_Client(Client *client, + const char *server = "io.adafruit.com", + uint16_t port = 1883, + const char *user = "", + const char *pass = "", + const char *cid = ""): + Adafruit_MQTT(server, port, user, pass, cid), client(client) {} diff --git a/Adafruit_MQTT_FONA.h b/Adafruit_MQTT_FONA.h index 204d10f..ec308f9 100644 --- a/Adafruit_MQTT_FONA.h +++ b/Adafruit_MQTT_FONA.h @@ -35,9 +35,13 @@ // 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, - const char *cid, const char *user, const char *pass): - Adafruit_MQTT(server, port, cid, user, pass), + Adafruit_MQTT_FONA(Adafruit_FONA *f, + const char *server = "io.adafruit.com", + uint16_t port = 1883, + const char *user = "", + const char *pass = "", + const char *cid = ""): + Adafruit_MQTT(server, port, user, pass, cid), fona(f) {} From 9a11d83cf51456699ea76604810f6e3bfac7c027 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Mon, 5 Oct 2015 15:26:02 -0400 Subject: [PATCH 24/29] removes client id from all example sketches --- Adafruit_MQTT.h | 2 +- examples/mqtt_cc3k/mqtt_cc3k.ino | 8 ++------ examples/mqtt_esp8266/mqtt_esp8266.ino | 4 ++-- examples/mqtt_fona/mqtt_fona.ino | 8 ++------ examples/mqtt_yun/mqtt_yun.ino | 8 ++------ 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index fc65b0a..382dd87 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -100,7 +100,7 @@ class Adafruit_MQTT_Subscribe; // forward decl class Adafruit_MQTT { public: Adafruit_MQTT(const char *server = "io.adafruit.com", - uint16_t port = 1883, + uint16_t port = 1883, const char *user = "", const char *pass = "", const char *cid = ""); diff --git a/examples/mqtt_cc3k/mqtt_cc3k.ino b/examples/mqtt_cc3k/mqtt_cc3k.ino index bce77ed..4fa3a26 100644 --- a/examples/mqtt_cc3k/mqtt_cc3k.ino +++ b/examples/mqtt_cc3k/mqtt_cc3k.ino @@ -45,18 +45,14 @@ // Setup the main CC3000 class, just like a normal CC3000 sketch. Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT); -// Store the MQTT server, client ID, username, and password in flash memory. +// Store the MQTT server, username, and password in flash memory. // This is required for using the Adafruit MQTT library. const char MQTT_SERVER[] PROGMEM = AIO_SERVER; -// Set a unique MQTT client ID using the AIO key + the date and time the sketch -// was compiled (so this should be unique across multiple devices for a user, -// alternatively you can manually set this to a GUID or other random value). -const char MQTT_CLIENTID[] PROGMEM = __TIME__ AIO_USERNAME; const char MQTT_USERNAME[] PROGMEM = AIO_USERNAME; const char MQTT_PASSWORD[] PROGMEM = AIO_KEY; // Setup the CC3000 MQTT class by passing in the CC3000 class and MQTT server and login details. -Adafruit_MQTT_CC3000 mqtt(&cc3000, MQTT_SERVER, AIO_SERVERPORT, MQTT_CLIENTID, MQTT_USERNAME, MQTT_PASSWORD); +Adafruit_MQTT_CC3000 mqtt(&cc3000, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD); // You don't need to change anything below this line! #define halt(s) { Serial.println(F( s )); while(1); } diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index ca72c59..75830c3 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -35,14 +35,14 @@ // Create an ESP8266 WiFiClient class to connect to the MQTT server. WiFiClient client; -// Store the MQTT server, client ID, username, and password in flash memory. +// Store the MQTT server, username, and password in flash memory. // This is required for using the Adafruit MQTT library. const char MQTT_SERVER[] PROGMEM = AIO_SERVER; const char MQTT_USERNAME[] PROGMEM = AIO_USERNAME; const char MQTT_PASSWORD[] PROGMEM = AIO_KEY; // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. -Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, "", MQTT_USERNAME, MQTT_PASSWORD); +Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD); /****************************** Feeds ***************************************/ diff --git a/examples/mqtt_fona/mqtt_fona.ino b/examples/mqtt_fona/mqtt_fona.ino index 4af766a..45c41cb 100644 --- a/examples/mqtt_fona/mqtt_fona.ino +++ b/examples/mqtt_fona/mqtt_fona.ino @@ -52,18 +52,14 @@ Adafruit_FONA fona = Adafruit_FONA(FONA_RST); /************ Global State (you don't need to change this!) ******************/ -// Store the MQTT server, client ID, username, and password in flash memory. +// Store the MQTT server, username, and password in flash memory. // This is required for using the Adafruit MQTT library. const char MQTT_SERVER[] PROGMEM = AIO_SERVER; -// Set a unique MQTT client ID using the AIO key + the date and time the sketch -// was compiled (so this should be unique across multiple devices for a user, -// alternatively you can manually set this to a GUID or other random value). -const char MQTT_CLIENTID[] PROGMEM = __TIME__ AIO_USERNAME; const char MQTT_USERNAME[] PROGMEM = AIO_USERNAME; const char MQTT_PASSWORD[] PROGMEM = AIO_KEY; // Setup the FONA MQTT class by passing in the FONA class and MQTT server and login details. -Adafruit_MQTT_FONA mqtt(&fona, MQTT_SERVER, AIO_SERVERPORT, MQTT_CLIENTID, MQTT_USERNAME, MQTT_PASSWORD); +Adafruit_MQTT_FONA mqtt(&fona, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD); // You don't need to change anything below this line! #define halt(s) { Serial.println(F( s )); while(1); } diff --git a/examples/mqtt_yun/mqtt_yun.ino b/examples/mqtt_yun/mqtt_yun.ino index cea49d6..33fa550 100644 --- a/examples/mqtt_yun/mqtt_yun.ino +++ b/examples/mqtt_yun/mqtt_yun.ino @@ -35,18 +35,14 @@ // Create a YunClient instance to communicate using the Yun's brighe & Linux OS. YunClient client; -// Store the MQTT server, client ID, username, and password in flash memory. +// Store the MQTT server, username, and password in flash memory. // This is required for using the Adafruit MQTT library. const char MQTT_SERVER[] PROGMEM = AIO_SERVER; -// Set a unique MQTT client ID using the AIO key + the date and time the sketch -// was compiled (so this should be unique across multiple devices for a user, -// alternatively you can manually set this to a GUID or other random value). -const char MQTT_CLIENTID[] PROGMEM = __TIME__ AIO_USERNAME; const char MQTT_USERNAME[] PROGMEM = AIO_USERNAME; const char MQTT_PASSWORD[] PROGMEM = AIO_KEY; // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. -Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_CLIENTID, MQTT_USERNAME, MQTT_PASSWORD); +Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD); /****************************** Feeds ***************************************/ From 286245ab6252300061b9d553c482224539dd2b90 Mon Sep 17 00:00:00 2001 From: ladyada Date: Wed, 21 Oct 2015 00:05:46 -0400 Subject: [PATCH 25/29] compile fix & #ifdef the MQTT version --- Adafruit_MQTT.cpp | 9 +++++++-- Adafruit_MQTT.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 8c461dd..ae7b062 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -84,6 +84,7 @@ Adafruit_MQTT::Adafruit_MQTT(const char *server, uint16_t port, subscriptions[i] = 0; } + packet_id_counter = 0; } Adafruit_MQTT::Adafruit_MQTT(const __FlashStringHelper *server, @@ -103,6 +104,7 @@ Adafruit_MQTT::Adafruit_MQTT(const __FlashStringHelper *server, subscriptions[i] = 0; } + packet_id_counter = 0; } int8_t Adafruit_MQTT::connect() { @@ -355,10 +357,13 @@ uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) { p+=2; // fill in packet[1] last - if(MQTT_PROTOCOL_LEVEL == 3) +#if MQTT_PROTOCOL_LEVEL == 3 p = stringprint_P(p, PSTR("MQIsdp")); - else +#elif MQTT_PROTOCOL_LEVEL == 4 p = stringprint_P(p, PSTR("MQTT")); +#else + #error "MQTT level not supported" +#endif p[0] = MQTT_PROTOCOL_LEVEL; p++; diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 382dd87..eaed311 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -201,7 +201,7 @@ class Adafruit_MQTT { uint8_t will_qos; uint8_t will_retain; uint8_t buffer[MAXBUFFERSIZE]; // one buffer, used for all incoming/outgoing - uint16_t packet_id_counter = 0; + uint16_t packet_id_counter; private: Adafruit_MQTT_Subscribe *subscriptions[MAXSUBSCRIPTIONS]; From 632c2f2cfe7a88291725f9fd2b8931d864a35367 Mon Sep 17 00:00:00 2001 From: ladyada Date: Wed, 21 Oct 2015 00:15:27 -0400 Subject: [PATCH 26/29] back compatible ping() --- Adafruit_MQTT.cpp | 25 +++++++++++++------------ Adafruit_MQTT.h | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index ae7b062..3721333 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -325,20 +325,21 @@ Adafruit_MQTT_Subscribe *Adafruit_MQTT::readSubscription(int16_t timeout) { return subscriptions[i]; } -bool Adafruit_MQTT::ping() { - - // Construct and send ping packet. - uint8_t len = pingPacket(buffer); - if (!sendPacket(buffer, len)) - return false; - - // Process ping reply. - len = readPacket(buffer, 2, PING_TIMEOUT_MS); - if (buffer[0] == (MQTT_CTRL_PINGRESP << 4)) - return true; +bool Adafruit_MQTT::ping(uint8_t num = 1) { + while (num--) { + // Construct and send ping packet. + uint8_t len = pingPacket(buffer); + if (!sendPacket(buffer, len)) + return false; + + // Process ping reply. + len = readPacket(buffer, 2, PING_TIMEOUT_MS); + if (buffer[0] == (MQTT_CTRL_PINGRESP << 4)) + return true; + } + return false; - } // Packet Generation Functions ///////////////////////////////////////////////// diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index eaed311..e88735a 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -169,7 +169,7 @@ class Adafruit_MQTT { Adafruit_MQTT_Subscribe *readSubscription(int16_t timeout=0); // Ping the server to ensure the connection is still alive. - bool ping(); + bool ping(uint8_t n); protected: // Interface that subclasses need to implement: From 2aed9ae73764c5b5f1369ba6fee4db484326c18a Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Thu, 22 Oct 2015 10:09:16 -0400 Subject: [PATCH 27/29] remove defaults from mqtt constructors --- Adafruit_MQTT.cpp | 53 ++++++++++++++++++++++++++++++++++++++---- Adafruit_MQTT.h | 28 ++++++++++++++-------- Adafruit_MQTT_CC3000.h | 16 +++++++------ Adafruit_MQTT_Client.h | 16 +++++++------ Adafruit_MQTT_FONA.h | 16 +++++++------ 5 files changed, 93 insertions(+), 36 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 3721333..094af2a 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -70,9 +70,11 @@ static uint8_t *stringprint_P(uint8_t *p, const char *s, uint16_t maxlen=0) { // Adafruit_MQTT Definition //////////////////////////////////////////////////// -Adafruit_MQTT::Adafruit_MQTT(const char *server, uint16_t port, - const char *user, const char *pass, - const char *cid) { +Adafruit_MQTT::Adafruit_MQTT(const char *server, + uint16_t port, + const char *cid, + const char *user, + const char *pass) { servername = server; portnum = port; clientid = cid; @@ -85,13 +87,14 @@ Adafruit_MQTT::Adafruit_MQTT(const char *server, uint16_t port, } packet_id_counter = 0; + } Adafruit_MQTT::Adafruit_MQTT(const __FlashStringHelper *server, uint16_t port, + const __FlashStringHelper *cid, const __FlashStringHelper *user, - const __FlashStringHelper *pass, - const __FlashStringHelper *cid) { + const __FlashStringHelper *pass) { servername = (const char *)server; portnum = port; @@ -105,6 +108,46 @@ Adafruit_MQTT::Adafruit_MQTT(const __FlashStringHelper *server, } packet_id_counter = 0; + +} + +Adafruit_MQTT::Adafruit_MQTT(const char *server, + uint16_t port, + const char *user, + const char *pass) { + servername = server; + portnum = port; + clientid = ""; + username = user; + password = pass; + + // reset subscriptions + for (uint8_t i=0; i Date: Thu, 22 Oct 2015 13:03:55 -0400 Subject: [PATCH 28/29] ping flushes input, tries multiple times --- Adafruit_MQTT.cpp | 11 +++++++++-- Adafruit_MQTT.h | 4 +++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index 094af2a..7a87f16 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -368,13 +368,20 @@ Adafruit_MQTT_Subscribe *Adafruit_MQTT::readSubscription(int16_t timeout) { return subscriptions[i]; } -bool Adafruit_MQTT::ping(uint8_t num = 1) { +void Adafruit_MQTT::flushIncoming(uint16_t timeout) { + // flush input! + DEBUG_PRINTLN(F("Flushing input buffer")); + while (readPacket(buffer, MAXBUFFERSIZE, timeout)); +} + +bool Adafruit_MQTT::ping(uint8_t num) { + flushIncoming(100); while (num--) { // Construct and send ping packet. uint8_t len = pingPacket(buffer); if (!sendPacket(buffer, len)) - return false; + continue; // Process ping reply. len = readPacket(buffer, 2, PING_TIMEOUT_MS); diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index 2b9341a..7bba0a4 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -178,7 +178,7 @@ class Adafruit_MQTT { Adafruit_MQTT_Subscribe *readSubscription(int16_t timeout=0); // Ping the server to ensure the connection is still alive. - bool ping(uint8_t n); + bool ping(uint8_t n = 1); protected: // Interface that subclasses need to implement: @@ -215,6 +215,8 @@ class Adafruit_MQTT { private: Adafruit_MQTT_Subscribe *subscriptions[MAXSUBSCRIPTIONS]; + void flushIncoming(uint16_t timeout); + // Functions to generate MQTT packets. uint8_t connectPacket(uint8_t *packet); uint8_t disconnectPacket(uint8_t *packet); From 4dc6f1e486cd02984a93e3d367d952ccb2d601ef Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Thu, 22 Oct 2015 14:13:19 -0400 Subject: [PATCH 29/29] adds ping to the end of the main loop in examples --- examples/mqtt_cc3k/mqtt_cc3k.ino | 16 +++---- examples/mqtt_esp8266/mqtt_esp8266.ino | 14 +++--- examples/mqtt_ethernet/mqtt_ethernet.ino | 13 +++--- examples/mqtt_fona/mqtt_fona.ino | 55 +++++++++++++----------- examples/mqtt_yun/mqtt_yun.ino | 14 +++--- 5 files changed, 55 insertions(+), 57 deletions(-) diff --git a/examples/mqtt_cc3k/mqtt_cc3k.ino b/examples/mqtt_cc3k/mqtt_cc3k.ino index 4fa3a26..c7db7ee 100644 --- a/examples/mqtt_cc3k/mqtt_cc3k.ino +++ b/examples/mqtt_cc3k/mqtt_cc3k.ino @@ -104,16 +104,6 @@ void loop() { // 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) ) { - // MQTT pings failed, let's reconnect by forcing a watchdog reset. - Serial.println("Ping fail! Resetting..."); - Watchdog.enable(8000); - delay(10000); - } - */ // this is our 'wait for incoming subscription packets' busy subloop Adafruit_MQTT_Subscribe *subscription; @@ -133,6 +123,12 @@ void loop() { } else { Serial.println(F("OK!")); } + + // ping the server to keep the mqtt connection alive + if(! mqtt.ping()) { + Serial.println(F("MQTT Ping failed.")); + } + } // Function to connect and reconnect as necessary to the MQTT server. diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index 75830c3..8defec1 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -90,14 +90,6 @@ void loop() { // function definition further below. MQTT_connect(); - // Try to ping the MQTT server - /* - if (! mqtt.ping(3) ) { - // MQTT pings failed, lets reconnect - Serial.println("Ping fail!"); - } - */ - // this is our 'wait for incoming subscription packets' busy subloop Adafruit_MQTT_Subscribe *subscription; while ((subscription = mqtt.readSubscription(1000))) { @@ -117,7 +109,13 @@ void loop() { Serial.println(F("OK!")); } + // ping the server to keep the mqtt connection alive + if(! mqtt.ping()) { + mqtt.disconnect(); + } + delay(1000); + } // Function to connect and reconnect as necessary to the MQTT server. diff --git a/examples/mqtt_ethernet/mqtt_ethernet.ino b/examples/mqtt_ethernet/mqtt_ethernet.ino index c27f8a8..ecb1a24 100644 --- a/examples/mqtt_ethernet/mqtt_ethernet.ino +++ b/examples/mqtt_ethernet/mqtt_ethernet.ino @@ -91,13 +91,6 @@ void loop() { // 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) ) { - // MQTT pings failed, let's reconnect by forcing a watchdog reset. - Serial.println("Ping fail! Resetting..."); - delay(10000); - } // this is our 'wait for incoming subscription packets' busy subloop Adafruit_MQTT_Subscribe *subscription; @@ -117,6 +110,12 @@ void loop() { } else { Serial.println(F("OK!")); } + + // ping the server to keep the mqtt connection alive + if(! mqtt.ping()) { + mqtt.disconnect(); + } + } // Function to connect and reconnect as necessary to the MQTT server. diff --git a/examples/mqtt_fona/mqtt_fona.ino b/examples/mqtt_fona/mqtt_fona.ino index 45c41cb..a7b00aa 100644 --- a/examples/mqtt_fona/mqtt_fona.ino +++ b/examples/mqtt_fona/mqtt_fona.ino @@ -113,30 +113,10 @@ void loop() { // Make sure to reset watchdog every loop iteration! Watchdog.reset(); - // check if we're still connected - if (!fona.TCPconnected() || (txfailures >= MAXTXFAILURES)) { - Serial.println(F("Connecting to MQTT...")); - int8_t ret, retries = 5; - while (retries && (ret = mqtt.connect()) != 0) { - Serial.println(mqtt.connectErrorString(ret)); - Serial.println(F("Retrying MQTT connection")); - retries--; - if (retries == 0) halt("Resetting system"); - delay(5000); - } - Serial.println(F("MQTT Connected!")); - txfailures = 0; - } - - - // Try to ping the MQTT server - /* - if (! mqtt.ping(3) ) { - // MQTT pings failed, lets reconnect - Serial.println("Ping fail!"); - } - */ - + // 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(); // this is our 'wait for incoming subscription packets' busy subloop Adafruit_MQTT_Subscribe *subscription; @@ -158,4 +138,31 @@ void loop() { Serial.println(F("OK!")); txfailures = 0; } + + // ping the server to keep the mqtt connection alive + if(! mqtt.ping()) { + Serial.println(F("MQTT Ping failed.")); + } + +} + +// 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 + Serial.println(mqtt.connectErrorString(ret)); + Serial.println("Retrying MQTT connection in 5 seconds..."); + mqtt.disconnect(); + delay(5000); // wait 5 seconds + } + Serial.println("MQTT Connected!"); } diff --git a/examples/mqtt_yun/mqtt_yun.ino b/examples/mqtt_yun/mqtt_yun.ino index 33fa550..b02d06d 100644 --- a/examples/mqtt_yun/mqtt_yun.ino +++ b/examples/mqtt_yun/mqtt_yun.ino @@ -74,14 +74,6 @@ void loop() { // function definition further below. MQTT_connect(); - // Try to ping the MQTT server - /* - if (! mqtt.ping(3) ) { - // MQTT pings failed, lets reconnect - Console.println("Ping fail!"); - } - */ - // this is our 'wait for incoming subscription packets' busy subloop Adafruit_MQTT_Subscribe *subscription; while ((subscription = mqtt.readSubscription(1000))) { @@ -101,7 +93,13 @@ void loop() { Console.println(F("OK!")); } + // ping the server to keep the mqtt connection alive + if(! mqtt.ping()) { + Serial.println(F("MQTT Ping failed.")); + } + delay(1000); + } // Function to connect and reconnect as necessary to the MQTT server.