• Callbacks Added to the Adafruit MQTT Library for Arduino

    v0.14.1 of the Adafruit MQTT Library for Arduino introduces subscription callbacks. This change will allow users to organize their code into separate blocks by attaching callbacks to feed and group subscriptions. Here’s a simplified example of what the change looks like:

    setup() {
    
      // add the rest of setup code here
    
      // register callback for feed
      onoffbutton.setCallback(onoffcallback);
    
    }
    
    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 in the full example for more info.
      MQTT_connect();
    
      // wait 10 seconds for subscription messages
      // since we have no other tasks in this example.
      mqtt.processPackets(10000);
    
      // keep the connection alive
      mqtt.ping();
    
    }
    
    void onoffcallback(char *data, uint16_t len) {
      Serial.print("Hey we're in a onoff callback, the button value is: ");
      Serial.println(data);
    }
    

    In the example above, you can see that we added the call to mqtt.processPackets(10000);. This tells the library to wait 10 seconds (10000ms) for incoming packets before moving on to the next task, and it will block all other code execution. If your sketch is only waiting for subscription messages, then 10 seconds might be a good timeout, but if your sketch handles other tasks, you may want to reduce the timeout to 1 second (1000ms).

    The full example with multiple feed subscriptions can be found in the Adafruit_MQTT Arduino Library on GitHub. You will need to install or update the Adafruit MQTT Library to version 0.14.1 in the Arduino Library Manager, and open the mqtt_esp8266_callback example to get started.

    Are these examples helpful? Please visit our IO forum and share your thoughts.

  • MQTT Error Reporting

    Unlike HTTP, the MQTT protocol does not provide a standard way of reporting errors to connected clients. This poses a problem for Adafruit IO, because there are multiple reasons why sending data to Adafruit IO might fail.

    Here are a few common examples:

    • Publishing data to an invalid topic
    • Publishing data to an unauthorized topic
    • Publishing data too fast (rate limit)
    • Exceeding the number of feeds for your account (10 currently)
    • Sending too large of a payload

    Adafruit IO is not a standard MQTT broker. Normally MQTT brokers will rebroadcast published data to any authorized subscribed client as soon as the data is received, so errors are rarely encountered.

    The standard MQTT pub/sub workflow looks something like this:

    standard mqtt flow

    Adafruit IO’s message flow is a bit more complicated, and looks something like this:

    adafruit io mqtt flow

    In the simplified example above, you can see that there are multiple steps that need to be completed before data is rebroadcasted to subscribed clients. If any of these steps fail, data will not make it back to subscribed clients. The reasons for failure are often unclear to users, so we added two special MQTT topics that will help inform users of any issues related to publishing data.

    The first topic you can subscribe to is the error topic for your user. This topic will receive any errors related to data validation and database saves. The topic path looks like this:

    {username}/errors
    

    For example, if your username was ladyada, you would subscribe to the following topic using your favorite MQTT client:

    ladyada/errors
    

    The second topic you can subscribe to is the throttle topic for your user. This topic contains any messages related to rate limits on your account. You might see these if you are publishing too fast. The topic path looks like this:

    {username}/throttle
    

    Again, if your username was ladyada, you would subscribe to the following topic:

    ladyada/throttle
    

    If you are using the Adafruit MQTT Library, you can define the throttle and error subscriptions at the top of your sketch like this:

    /*************************** Error Reporting *********************************/
    
    const char ERRORS[] PROGMEM = AIO_USERNAME "/errors";
    Adafruit_MQTT_Subscribe errors = Adafruit_MQTT_Subscribe(&mqtt, ERRORS);
    
    const char THROTTLE[] PROGMEM = AIO_USERNAME "/throttle";
    Adafruit_MQTT_Subscribe throttle = Adafruit_MQTT_Subscribe(&mqtt, THROTTLE);
    

    Then, subscribe to the topics at the bottom of the setup function:

    void setup() {
    
      // ...network connection setup code here
    
      // MQTT subscriptions for throttle & error messages
      mqtt.subscribe(&throttle);
      mqtt.subscribe(&errors);
    
    }
    
    

    Finally, inside of the main loop, print any errors to the serial monitor:

    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();
    
      // this is our 'wait for incoming subscription packets' busy subloop
      // try to spend your time here
      Adafruit_MQTT_Subscribe *subscription;
      while ((subscription = mqtt.readSubscription(5000))) {
        if(subscription == &errors) {
          Serial.print(F("ERROR: "));
          Serial.println((char *)errors.lastread);
        } else if(subscription == &throttle) {
          Serial.print(F("THROTTLED: "));
          Serial.println((char *)throttle.lastread);
        }
      }
    
      mqtt.ping();
    
    }
    

    You can see the full example for the ESP8266 in the Adafruit_MQTT Arduino Library on GitHub. Install or update the Adafruit MQTT Library to version 0.13.3 in the Arduino Library Manager, and open the adafruitio_errors_esp8266 example to get started.

    Are these examples helpful? Please visit our IO forum and share your thoughts.

  • IoT Security: Connecting Your ESP8266 to Adafruit IO with SSL/TLS

    The ESP8266 based Adafruit HUZZAH breakout and the Adafruit Feather HUZZAH are both popular options to use with Adafruit IO. Because ESP8266 SSL/TLS support is fairly new, most of our Adafruit IO examples use the insecure MQTT port 1883.

    Why is this a problem? The MQTT protocol is an insecure protocol on it’s own. All data (including username & password) are sent in the clear, so SSL/TLS is required to protect any sensitive information.

    What are SSL & TLS? Transport Layer Security (TLS) and its predecessor, Secure Sockets Layer (SSL), are cryptographic protocols that you use whenever you browse the internet. Have you ever noticed the lock symbol 🔒 in your browser’s URL bar? That lock symbol represents a secure connection between your browser & a web site over SSL/TLS. We use those same protocols to secure traffic between your ESP8266 and Adafruit IO.

    We have added an example to the Adafruit_MQTT Arduino Library that you can use to secure communication between your ESP8266 and Adafruit IO. Install or update the Adafruit MQTT Library to version 0.13.2 in the Arduino Library Manager, and open the adafruitio_secure_esp8266 example to get started.

    example

    The main changes to the standard ESP8266 example are that WiFiClientSecure is used in place of WiFiClient, and port 8883 is used instead of MQTT port 1883. The sketch also checks the fingerprint for the io.adafruit.com certificate using the verifyFingerprint function.

    A simplified summary of the changes can be seen below:

    #define AIO_SERVER      "io.adafruit.com"
    #define AIO_SERVERPORT  8883                   // 8883 for MQTTS
    
    // WiFiFlientSecure for SSL/TLS support
    WiFiClientSecure client;
    
    // io.adafruit.com SHA1 fingerprint
    const char* fingerprint = "26 96 1C 2A 51 07 FD 15 80 96 93 AE F7 32 CE B9 0D 01 55 C4";
    
    void verifyFingerprint() {
    
      const char* host = AIO_SERVER;
    
      Serial.print("Connecting to ");
      Serial.println(host);
    
      if (! client.connect(host, AIO_SERVERPORT)) {
        Serial.println("Connection failed. Halting execution.");
        while(1);
      }
    
      if (client.verify(fingerprint, host)) {
        Serial.println("Connection secure.");
      } else {
        Serial.println("Connection insecure! Halting execution.");
        while(1);
      }
    
    }
    
    
  • From the Forums: Two Buttons & Two LEDs

    User smcculley posted a useful example in the IO Forum:

    I have had some requests from people to share my code to talk to Adafruit IO using MQTT and being able to trigger two LED’s.

    Note that I am using the latest AdafruitIO MQTT code from GitHub, as it has the latest fixes available: https://github.com/adafruit/Adafruit_MQTT_Library

    In Adafruit IO, I created two feeds, called ledone and ledtwo, and added them to a group called leds. I then created a dashboard with two toggle switches, and tied them to the feeds (one to each, obviously) using the default ON and OFF button text.

    Check out the post for more details. Thanks for sharing!

  • Extending the MQTT Protocol

    Last month we deployed a change to Adafruit IO’s MQTT broker that allowed us to rate limit connection attempts. Although we don’t like to throttle or ban users, the change was necessary to protect Adafruit IO from abuse, and ensure the overall health of the service.

    This presented a problem: How do we inform users when they have been throttled or banned? Ideally the MQTT protocol would allow for us to inform the user using a standard response, but currently the connection acknowledgement packet (CONNACK) has a limited set of response codes.

    The MQTT v3.1.1 protocol has the following values defined for the CONNACK packet response code:

    Value

    Return Code Response

    Description

    0

    0x00 Connection Accepted

    Connection accepted

    1

    0x01 Connection Refused, unacceptable protocol version

    The Server does not support the level of the MQTT protocol requested by the Client

    2

    0x02 Connection Refused, identifier rejected

    The Client identifier is correct UTF-8 but not allowed by the Server

    3

    0x03 Connection Refused, Server unavailable

    The Network Connection has been made but the MQTT service is unavailable

    4

    0x04 Connection Refused, bad user name or password

    The data in the user name or password is malformed

    5

    0x05 Connection Refused, not authorized

    The Client is not authorized to connect

    6-255

     

    Reserved for future use

    The current set of codes didn’t allow us to clearly communicate the reason for disconnects to our users. We have extended the list of codes in the CONNACK packet to include connection throttle (0x06) and ban (0x07).

    Value

    Return Code Response

    Description

    6

    0x06 Connection Refused, throttled

    Client has exceeded connection rate limit. Please try again later.

    7

    0x07 Connection Refused, banned

    The client has been banned by the server administrator.

    We have submitted these two new codes to the OASIS MQTT Technical Committee for comment, and we are adding support to our MQTT client libraries. If you would like to comment on these changes, please visit our IO forum and share your thoughts.