diff --git a/Adafruit_MQTT.cpp b/Adafruit_MQTT.cpp index ad147f9..93b63c6 100644 --- a/Adafruit_MQTT.cpp +++ b/Adafruit_MQTT.cpp @@ -47,9 +47,8 @@ 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 PROGMEM char *cid, const PROGMEM char *user, - const PROGMEM char *pass) { +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; @@ -184,7 +183,6 @@ Adafruit_MQTT_Subscribe *Adafruit_MQTT::readSubscription(int16_t timeout) { // Stop if the subscription topic matches the received topic. Be careful // to make comparison case insensitive. if (strncasecmp_P((char*)buffer+4, subscriptions[i]->topic, topiclen) == 0) { - DEBUG_PRINTLN(subscriptions[i]->topic); DEBUG_PRINT(F("Found sub #")); DEBUG_PRINTLN(i); break; } diff --git a/Adafruit_MQTT.h b/Adafruit_MQTT.h index a2bf4e8..bea6924 100644 --- a/Adafruit_MQTT.h +++ b/Adafruit_MQTT.h @@ -71,8 +71,8 @@ class Adafruit_MQTT_Subscribe; // forward decl class Adafruit_MQTT { public: - Adafruit_MQTT(const char *server, uint16_t port, const PROGMEM char *cid, - const PROGMEM char *user, const PROGMEM char *pass); + Adafruit_MQTT(const char *server, uint16_t port, const char *cid, + const char *user, const char *pass); virtual ~Adafruit_MQTT() {} // Connect to the MQTT server. Returns 0 on success, otherwise an error code diff --git a/Adafruit_MQTT_CC3000.cpp b/Adafruit_MQTT_CC3000.cpp deleted file mode 100644 index 36d7816..0000000 --- a/Adafruit_MQTT_CC3000.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include "Adafruit_MQTT.h" -#include "Adafruit_MQTT_CC3000.h" - - -bool Adafruit_MQTT_CC3000::connectServer(void) { - uint32_t ip = 0; - - Watchdog.reset(); - - // look up IP address - if (serverip == 0) { - // Try looking up the website's IP address using CC3K's built in getHostByName - strcpy_P((char *)buffer, servername); - Serial.print((char *)buffer); Serial.print(F(" -> ")); - uint8_t dnsretries = 5; - - Watchdog.reset(); - while (ip == 0) { - if (! cc3000->getHostByName((char *)buffer, &ip)) { - Serial.println(F("Couldn't resolve!")); - dnsretries--; - Watchdog.reset(); - } - //Serial.println("OK"); Serial.println(ip, HEX); - if (!dnsretries) return false; - delay(500); - } - - serverip = ip; - cc3000->printIPdotsRev(serverip); - Serial.println(); - } - - Watchdog.reset(); - - // connect to server - DEBUG_PRINTLN(F("Connecting to TCP")); - mqttclient = cc3000->connectTCP(serverip, portnum); - - return mqttclient.connected(); -} - -bool Adafruit_MQTT_CC3000::disconnect(void) { - return (mqttclient.close() == 0); -} - -uint16_t Adafruit_MQTT_CC3000::readPacket(uint8_t *buffer, uint8_t maxlen, - int16_t timeout, - bool checkForValidPubPacket) { - /* Read data until either the connection is closed, or the idle timeout is reached. */ - uint16_t len = 0; - int16_t t = timeout; - - while (mqttclient.connected() && (timeout >= 0)) { - //DEBUG_PRINT('.'); - while (mqttclient.available()) { - //DEBUG_PRINT('!'); - char c = mqttclient.read(); - timeout = t; // reset the timeout - buffer[len] = c; - //DEBUG_PRINTLN((uint8_t)c, HEX); - len++; - if (len == maxlen) { // we read all we want, bail - DEBUG_PRINT(F("Read packet:\t")); - DEBUG_PRINTBUFFER(buffer, len); - return len; - } - - // special case where we just one one publication packet at a time - if (checkForValidPubPacket) { - if ((buffer[0] == (MQTT_CTRL_PUBLISH << 4)) && (buffer[1] == len-2)) { - // oooh a valid publish packet! - DEBUG_PRINT(F("Read PUBLISH packet:\t")); - DEBUG_PRINTBUFFER(buffer, len); - return len; - } - } - } - Watchdog.reset(); - timeout -= MQTT_CC3000_INTERAVAILDELAY; - delay(MQTT_CC3000_INTERAVAILDELAY); - } - return len; -} - -bool Adafruit_MQTT_CC3000::sendPacket(uint8_t *buffer, uint8_t len) { - if (mqttclient.connected()) { - uint16_t ret = mqttclient.write(buffer, len); - DEBUG_PRINT(F("sendPacket returned: ")); DEBUG_PRINTLN(ret); - if (ret != len) { - DEBUG_PRINTLN("Failed to send complete packet.") - return false; - } - } else { - DEBUG_PRINTLN(F("Connection failed!")); - return false; - } - return true; -} diff --git a/Adafruit_MQTT_CC3000.h b/Adafruit_MQTT_CC3000.h index 8921b4d..f75cad8 100644 --- a/Adafruit_MQTT_CC3000.h +++ b/Adafruit_MQTT_CC3000.h @@ -1,6 +1,7 @@ #ifndef _ADAFRUIT_MQTT_CC3000_H_ #define _ADAFRUIT_MQTT_CC3000_H_ +#include #include #include "Adafruit_MQTT.h" @@ -8,6 +9,10 @@ #define MQTT_CC3000_INTERAVAILDELAY 10 +// CC3000-specific version of the Adafruit_MQTT class. +// Note that this is defined as a header-only class to prevent issues with using +// the library on non-CC3000 platforms (since Arduino will include all .cpp files +// 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, @@ -16,11 +21,100 @@ class Adafruit_MQTT_CC3000 : public Adafruit_MQTT { cc3000(cc3k) {} - bool connectServer(); - bool disconnect(); + bool connectServer() { + uint32_t ip = 0; + + Watchdog.reset(); + + // look up IP address + if (serverip == 0) { + // Try looking up the website's IP address using CC3K's built in getHostByName + strcpy_P((char *)buffer, servername); + Serial.print((char *)buffer); Serial.print(F(" -> ")); + uint8_t dnsretries = 5; + + Watchdog.reset(); + while (ip == 0) { + if (! cc3000->getHostByName((char *)buffer, &ip)) { + Serial.println(F("Couldn't resolve!")); + dnsretries--; + Watchdog.reset(); + } + //Serial.println("OK"); Serial.println(ip, HEX); + if (!dnsretries) return false; + delay(500); + } + + serverip = ip; + cc3000->printIPdotsRev(serverip); + Serial.println(); + } + + Watchdog.reset(); + + // connect to server + DEBUG_PRINTLN(F("Connecting to TCP")); + mqttclient = cc3000->connectTCP(serverip, portnum); + + return mqttclient.connected(); + } + + bool disconnect() { + return (mqttclient.close() == 0); + } + uint16_t readPacket(uint8_t *buffer, uint8_t maxlen, int16_t timeout, - bool checkForValidPubPacket = false); - bool sendPacket(uint8_t *buffer, uint8_t len); + bool checkForValidPubPacket = false) { + /* Read data until either the connection is closed, or the idle timeout is reached. */ + uint16_t len = 0; + int16_t t = timeout; + + while (mqttclient.connected() && (timeout >= 0)) { + //DEBUG_PRINT('.'); + while (mqttclient.available()) { + //DEBUG_PRINT('!'); + char c = mqttclient.read(); + timeout = t; // reset the timeout + buffer[len] = c; + //DEBUG_PRINTLN((uint8_t)c, HEX); + len++; + if (len == maxlen) { // we read all we want, bail + DEBUG_PRINT(F("Read packet:\t")); + DEBUG_PRINTBUFFER(buffer, len); + return len; + } + + // special case where we just one one publication packet at a time + if (checkForValidPubPacket) { + if ((buffer[0] == (MQTT_CTRL_PUBLISH << 4)) && (buffer[1] == len-2)) { + // oooh a valid publish packet! + DEBUG_PRINT(F("Read PUBLISH packet:\t")); + DEBUG_PRINTBUFFER(buffer, len); + return len; + } + } + } + Watchdog.reset(); + timeout -= MQTT_CC3000_INTERAVAILDELAY; + delay(MQTT_CC3000_INTERAVAILDELAY); + } + return len; + } + + bool sendPacket(uint8_t *buffer, uint8_t len) { + if (mqttclient.connected()) { + uint16_t ret = mqttclient.write(buffer, len); + DEBUG_PRINT(F("sendPacket returned: ")); DEBUG_PRINTLN(ret); + if (ret != len) { + DEBUG_PRINTLN("Failed to send complete packet.") + return false; + } + } else { + DEBUG_PRINTLN(F("Connection failed!")); + return false; + } + return true; + } private: uint32_t serverip; diff --git a/Adafruit_MQTT_Client.cpp b/Adafruit_MQTT_Client.cpp new file mode 100644 index 0000000..c956876 --- /dev/null +++ b/Adafruit_MQTT_Client.cpp @@ -0,0 +1,72 @@ +#include "Adafruit_MQTT_Client.h" + + +bool Adafruit_MQTT_Client::connectServer() { + // Grab server name from flash and copy to buffer for name resolution. + memset(buffer, 0, sizeof(buffer)); + strcpy_P((char *)buffer, servername); + DEBUG_PRINT(F("Connecting to: ")); DEBUG_PRINTLN((char *)buffer); + // Connect and check for success (0 result). + int r = client->connect((char *)buffer, portnum); + DEBUG_PRINT(F("Connect result: ")); DEBUG_PRINTLN(r); + return r != 0; +} + +bool Adafruit_MQTT_Client::disconnect() { + // Stop connection and return success (stop has no indication of failure). + client->stop(); + return true; +} + +uint16_t Adafruit_MQTT_Client::readPacket(uint8_t *buffer, uint8_t maxlen, + int16_t timeout, + bool checkForValidPubPacket) { + /* Read data until either the connection is closed, or the idle timeout is reached. */ + uint16_t len = 0; + int16_t t = timeout; + + while (client->connected() && (timeout >= 0)) { + //DEBUG_PRINT('.'); + while (client->available()) { + //DEBUG_PRINT('!'); + char c = client->read(); + timeout = t; // reset the timeout + buffer[len] = c; + //DEBUG_PRINTLN((uint8_t)c, HEX); + len++; + if (len == maxlen) { // we read all we want, bail + DEBUG_PRINT(F("Read packet:\t")); + DEBUG_PRINTBUFFER(buffer, len); + return len; + } + + // special case where we just one one publication packet at a time + if (checkForValidPubPacket) { + if ((buffer[0] == (MQTT_CTRL_PUBLISH << 4)) && (buffer[1] == len-2)) { + // oooh a valid publish packet! + DEBUG_PRINT(F("Read PUBLISH packet:\t")); + DEBUG_PRINTBUFFER(buffer, len); + return len; + } + } + } + timeout -= MQTT_CLIENT_READINTERVAL_MS; + delay(MQTT_CLIENT_READINTERVAL_MS); + } + return len; +} + +bool Adafruit_MQTT_Client::sendPacket(uint8_t *buffer, uint8_t len) { + if (client->connected()) { + uint16_t ret = client->write(buffer, len); + DEBUG_PRINT(F("sendPacket returned: ")); DEBUG_PRINTLN(ret); + if (ret != len) { + DEBUG_PRINTLN("Failed to send complete packet.") + return false; + } + } else { + DEBUG_PRINTLN(F("Connection failed!")); + return false; + } + return true; +} diff --git a/Adafruit_MQTT_Client.h b/Adafruit_MQTT_Client.h new file mode 100644 index 0000000..7d9e4b5 --- /dev/null +++ b/Adafruit_MQTT_Client.h @@ -0,0 +1,34 @@ +#ifndef _ADAFRUIT_MQTT_CLIENT_H_ +#define _ADAFRUIT_MQTT_CLIENT_H_ + +#include "Client.h" +#include "Adafruit_MQTT.h" + +// How long to delay waiting for new data to be available in readPacket. +#define MQTT_CLIENT_READINTERVAL_MS 10 + +// MQTT client implementation for a generic Arduino Client interface. Can work +// with almost all Arduino network hardware like ethernet shield, wifi shield, +// 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), + client(client) + {} + + bool connectServer(); + bool disconnect(); + 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; +}; + + +#endif diff --git a/examples/AIO_ESP8266/AIO_ESP8266.ino b/examples/AIO_ESP8266/AIO_ESP8266.ino new file mode 100644 index 0000000..bd7c3c6 --- /dev/null +++ b/examples/AIO_ESP8266/AIO_ESP8266.ino @@ -0,0 +1,128 @@ +// Adafruit IO MQTT Example for ESP8266. +// Must be using ESP8266 Arduino from: +// https://github.com/esp8266/Arduino +#include +#include "Adafruit_MQTT.h" +#include "Adafruit_MQTT_Client.h" + +/************************* WiFi Access Point *********************************/ + +#define WLAN_SSID "...your SSID..." +#define WLAN_PASS "...your password..." + +/************************* Adafruit.io Setup *********************************/ + +#define AIO_SERVER "io.adafruit.com" +#define AIO_SERVERPORT 1883 +#define AIO_USERNAME "...your AIO username (see https://accounts.adafruit.com)..." +#define AIO_KEY "...your AIO key..."; + +/* Debug server configuration (not normally used): +#define AIO_SERVER "apt.adafruit.com" +#define AIO_SERVERPORT 1883 +*/ + +/************ Global State (you don't need to change this!) ******************/ + +// 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. +// This is required for using the Adafruit MQTT library. +const char MQTT_SERVER[] PROGMEM = AIO_SERVER; +const char MQTT_CLIENTID[] PROGMEM = AIO_KEY; +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); + +/****************************** Feeds ***************************************/ + +// Setup a feed called 'photocell' for publishing. +// Notice MQTT paths for AIO follow the form: /feeds/ +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. +const char ONOFF_FEED[] PROGMEM = AIO_USERNAME "/feeds/onoff"; +Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, ONOFF_FEED); + +/*************************** Sketch Code ************************************/ + +void setup() { + Serial.begin(115200); + delay(10); + + Serial.println(F("Adafruit MQTT demo")); + + // Connect to WiFi access point. + 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); + Serial.print("."); + } + Serial.println(); + + 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() { + // 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)) { + if (subscription == &onoffbutton) { + Serial.print(F("Got: ")); + Serial.println((char *)onoffbutton.lastread); + } + } + + // Now we can publish stuff! + Serial.print(F("\nSending photocell val ")); + Serial.print(x); + Serial.print("..."); + if (! photocell.publish(x++)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + + delay(1000); +}