AdafruitAIO

AdafruitAIO is a special class the inherits from AdafruitMQTT (described earlier in this learning guide).  It takes the core features from AdafruitMQTT and adds some helper functions that make working with Adafruit IO easier.

If you're unfamiliar with Adafruit IO have a look at our introductory learning guide here: https://learn.adafruit.com/adafruit-io

Constructor

Download: file
AdafruitAIO(const char* username, const char* password)

Parameters:

  • username: The username associated with your Adafruit IO account (normally visible here).
  • password: The Adafruit IO key associated with your account.  This is available by logging into Adafruit IO and clicking the yellow 'key' icon labelled 'Your secret AIO key'.
By default AdafruitAIO will generate a random 10..23 character string for the ClientID. If required you can override the default value via the .clientID function if it is called BEFORE the .connect or .connectSSL functions.

Functions

In addition to the functions defined in the AdafruitMQTT base class, The following functions are included as part of AdafruitAIO:

Download: file
bool connect      ( bool cleanSession = true,
                    uint16_t keepalive_sec = MQTT_KEEPALIVE_DEFAULT )
  
bool connectSSL   ( bool cleanSession = true, 
                    uint16_t keepalive_sec = MQTT_KEEPALIVE_DEFAULT )

bool updateFeed   ( const char* feed, 
                    UTF8String message, 
                    uint8_t qos=MQTT_QOS_AT_MOST_ONCE,
                    bool retain=true )
  
bool followFeed   ( const char* feed, 
                    uint8_t qos, 
                    messageHandler_t mh )
  
bool unfollowFeed ( const char* feed )

Connecting

The following functions are available to connect to the Adafruit IO server:

bool connect (bool cleanSession = true, uint16_t keepalive_sec = MQTT_KEEPALIVE_DEFAULT)

This function will attempt to connect to the Adafruit IO servers using a standard (unencrypted) connection.

Parameters:

  • cleanSession: Indicates whether the client and broker should remember 'state' across restarts and reconnects. 'State' maintenance is based on the Client ID so be sure to set a reusable value via .clientID if you set cleanSession to false!:
    • If set to false (0) both the client and server will maintain state across restarts of the client, the server and the connection. As state is maintained:
      • Message delivery will be reliable meeting the specified QOS even if the client, server or connection are restarted.
      • The server will treat a subscription as durable.
    • If set to true (1) the client and server will not maintain state across restarts of the client, the server or the connection. This means:
      • Message delivery to the specified QOS cannot be maintained if the client, server or connection are restarted
      • The server will treat a subscription as non-durable
  • keepalive_sec: This value defines the maximum interval (in seconds) between messages being sent or received. Setting a value here ensures that at least one message is sent between the client and the broker within every 'keep alive' period. If no data was sent within 'keepalive_sec' seconds, the Client will send a simple ping to the broker to keep the connection alive. Setting this value to '0' disables the keep alive feature. The default value is 60 seconds.

Returns: 'True' (1) if the connection was successful, otherwise 'false' (0).

bool connectSSL (bool cleanSession = true, uint16_t keepalive_sec = MQTT_KEEPALIVE_DEFAULT)

This function will attempt to connect to the Adafruit IO servers using a secure (TLS/SSL) connection.

Parameters:

  • cleanSession: Indicates whether the client and broker should remember 'state' across restarts and reconnects. 'State' maintenance is based on the Client ID so be sure to set a reusable value via .clientID if you set cleanSession to false!:
    • If set to false (0) both the client and server will maintain state across restarts of the client, the server and the connection. As state is maintained:
      • Message delivery will be reliable meeting the specified QOS even if the client, server or connection are restarted.
      • The server will treat a subscription as durable.
    • If set to true (1) the client and server will not maintain state across restarts of the client, the server or the connection. This means:
      • Message delivery to the specified QOS cannot be maintained if the client, server or connection are restarted
      • The server will treat a subscription as non-durable
  • keepalive_sec: This value defines the maximum interval (in seconds) between messages being sent or received. Setting a value here ensures that at least one message is sent between the client and the broker within every 'keep alive' period. If no data was sent within 'keepalive_sec' seconds, the Client will send a simple ping to the broker to keep the connection alive. Setting this value to '0' disables the keep alive feature. The default value is 60 seconds.

Returns: 'True' (1) if the connection was successful, otherwise 'false' (0).

Feed Management

The following functions are available to work with AIO feeds:

bool updateFeed ( const char* feed, UTF8String message, uint8_t qos=MQTT_QOS_AT_MOST_ONCE, bool retain=true )

Updates the value associated with the specified 'feed' ('topic' in MQTT terminology).

Parameters:

  • feed: The feed to update, not including the 'username/feeds/' prefix. So to work with 'username/feeds/onoff' you should simply supply 'onoff' as the feedname.
  • qos: The quality of service level (see the MQTT spec for details).  Default = 'At Most Once', meaning the message tries to send once but isn't persisted if the send fails.  Possible values are:
    • MQTT_QOS_AT_MOST_ONCE
    • MQTT_QOS_AT_LEAST_ONCE
    • MQTT_QOS_EXACTLY_ONCE
  • retained: Whether or not the published message should be 'retained' by the MQTT broker. Sending a message with the retained bool set to 'false' (0) will clear any previously retained message from the broker. The default value is false.

Returns: 'True' (1) if the feed was succesfully updated, otherwise 'false' (0).

bool followFeed ( const char* feed,  uint8_t qos, messageHandler_t mh )

Follows (or 'subscribes' in MQTT terminology) to the specified AIO feed, which will cause the specific callback handler function to fire every time the feed is changed on the AIO server.

Parameters:

  • feed: The feed to follow, not including the 'username/feeds/' prefix. So to work with 'username/feeds/onoff' you should simply supply 'onoff' as the feedname.
  • qos: The quality of service level (see the MQTT spec for details).  Default = 'At Most Once', meaning the message tries to send once but isn't persisted if the send fails.  Possible values are:
    • MQTT_QOS_AT_MOST_ONCE
    • MQTT_QOS_AT_LEAST_ONCE
    • MQTT_QOS_EXACTLY_ONCE
  • mh: The callback handler function to fire whenever the feed is changed.  The callback handler should have the following signature:
Download: file
/**************************************************************************/
/*!
    @brief  'follow' event callback handler

    @param  message    The new value associated with this feed

    @note   'message' is a UTF8String (byte array), which means
            it is not null-terminated like C-style strings. You can
            access its data and len using .data & .len, although there is
            also a Serial.print override to handle UTF8String data types.
*/
/**************************************************************************/
void feed_callback(UTF8String message)
{
  // Print message
  Serial.println(message);
}

Returns: 'True' (1) if the follow operation was successful, otherwise 'false' (0).

bool unfollowFeed ( const char* feed )

Unfollows (or 'unsubscribes' in MQTT terminology) to the specified feed.

Parameters:

  • feed: The feed to update, not including the 'username/feeds/' prefix. So to work with 'username/feeds/onoff' you should simply supply 'onoff' as the feedname.

Returns: 'True' (1) if the operation was successful, otherwise 'false' (0).

Example

The following example show how you can use the AdafruitAIO class to communicate with the Adafruit IO servers:

Download: file
/*********************************************************************
 This is an example for our Feather WIFI modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

#include <adafruit_feather.h>
#include <adafruit_mqtt.h>
#include "certificate_mosquitto.h"

/* This sketch demonstrates subscribe/unsubscribe activity with
 * callbacks.
 * 
 * It will connect to a public MQTT server (with/without TLS)
 * and subscribe to TOPIC_SUBSCRIBE (defined below).
 * 
 * - When a message is received, it will echo back to TOPIC_ECHO
 * - If the received message is "stop", we will
 *   unsubscribe from TOPIC_SUBSCRIBE and you won't be able to
 *   echo content back to the broker any longer.
 * 
 * Note: TOPIC_SUBSCRIBE and TOPIC_ECHO must not be the same topic!
 * Ex. They must not be "adafruit/+" and "adafruit/echo", since this will
 * cause an infinite loop (received -> echo -> received -> ....)
 *
 * For details on the MQTT broker server see http://test.mosquitto.org/
 *  - Port 1883 : MQTT, unencrypted
 *  - Port 8883 : MQTT, encrypted (TLS)
 *
 * Note: may You need an MQTT desktop client such as the lightweight
 * Java client included in this repo: org.eclipse.paho.mqtt.utility-1.0.0.jar
 * 
 * For information on configuring your system to work with MQTT see:
 * - https://learn.adafruit.com/desktop-mqtt-client-for-adafruit-io/installing-software
 *
 * To run this demo
 * 1. Change the WLAN_SSID/WLAN_PASS to match your access point
 * 2. Decide whether you want to use TLS/SSL or not (USE_TLS)
 * 3. Change TOPIC*, WILL*, enable CLIENTID if needed
 * 4. Compile and run
 * 5. Use an MQTT desktop client to connect to the same MQTT broker and
 *    publish to any topic beginning with "adafruit/feather/" (depending
 *    on TOPIC_SUBSCRIBE). To be able to recieve the echo message, please
 *    also subcribe to "adafruit/feather_echo" (TOPIC_ECHO).
 */

#define WLAN_SSID         "yourSSID"
#define WLAN_PASS         "yourPass"

#define USE_TLS           0

#define BROKER_HOST       "test.mosquitto.org"
#define BROKER_PORT       (USE_TLS ? 8883 : 1883)

// Uncomment to set your own ClientID, otherwise a random ClientID is used
//#define CLIENTID          "Adafruit Feather"

#define TOPIC_SUBSCRIBE   "adafruit/feather/+"
#define TOPIC_ECHO        "adafruit/feather_echo"

#define WILL_TOPIC        "adafruit/feather"
#define WILL_MESSAGE      "Goodbye!!"

AdafruitMQTT mqtt;

/**************************************************************************/
/*!
    @brief  Disconnect handler for MQTT broker connection
*/
/**************************************************************************/
void disconnect_callback(void)
{
  Serial.println();
  Serial.println("-----------------------------");
  Serial.println("DISCONNECTED FROM MQTT BROKER");
  Serial.println("-----------------------------");
  Serial.println();
}

/**************************************************************************/
/*!
    @brief  The setup function runs once when the board comes out of reset
*/
/**************************************************************************/
void setup()
{
  Serial.begin(115200);

  // Wait for the USB serial port to connect. Needed for native USB port only
  while (!Serial) delay(1);

  Serial.println("MQTT Subscribe Example\r\n");

  // Print all software versions
  Feather.printVersions();

  while ( !connectAP() )
  {
    delay(500); // delay between each attempt
  }

  // Connected: Print network info
  Feather.printNetwork();

  // Tell the MQTT client to auto print error codes and halt on errors
  mqtt.err_actions(true, true);

  // Set ClientID if defined
  #ifdef CLIENTID
  mqtt.clientID(CLIENTID);
  #endif

  // Last will must be set before connecting since it is part of the connection data
  mqtt.will(WILL_TOPIC, WILL_MESSAGE, MQTT_QOS_AT_LEAST_ONCE);

  // Set the disconnect callback handler
  mqtt.setDisconnectCallback(disconnect_callback);

  Serial.printf("Connecting to " BROKER_HOST " port %d ... ", BROKER_PORT);
  if (USE_TLS)
  {  
    // Disable default RootCA to save SRAM since we don't need to
    // access any other site except test.mosquitto.org
    Feather.useDefaultRootCA(false);

    // mosquitto CA is pre-generated using pycert.py
    Feather.addRootCA(rootca_certs, ROOTCA_CERTS_LEN);

    // Connect with SSL/TLS
    mqtt.connectSSL(BROKER_HOST, BROKER_PORT);
  }else
  {
    mqtt.connect(BROKER_HOST, BROKER_PORT);
  }
  Serial.println("OK");

  Serial.print("Subscribing to " TOPIC_SUBSCRIBE " ... ");
  mqtt.subscribe(TOPIC_SUBSCRIBE, MQTT_QOS_AT_MOST_ONCE, subscribed_callback); // Will halted if an error occurs
  Serial.println("OK");
}

/**************************************************************************/
/*!
    @brief  This loop function runs over and over again
*/
/**************************************************************************/
void loop()
{

}

/**************************************************************************/
/*!
    @brief  MQTT subscribe event callback handler

    @param  topic      The topic causing this callback to fire
    @param  message    The new value associated with 'topic'

    @note   'topic' and 'message' are UTF8Strings (byte array), which means
            they are not null-terminated like C-style strings. You can
            access its data and len using .data & .len, although there is
            also a Serial.print override to handle UTF8String data types.
*/
/**************************************************************************/
void subscribed_callback(UTF8String topic, UTF8String message)
{
  // Print out topic name and message
  Serial.print("[Subscribed] ");
  Serial.print(topic);
  Serial.print(" : ") ;
  Serial.println(message);

  // Echo back
  Serial.print("Echo back to " TOPIC_ECHO " ... ");
  mqtt.publish(TOPIC_ECHO, message); // Will halt if an error occurs
  Serial.println("OK");

  // Unsubscribe from SUBSCRIBED_TOPIC2 if we received an "stop" message
  // Won't be able to echo anymore
  if ( message == "stop" )
  {
    Serial.print("Unsubscribing from " TOPIC_SUBSCRIBE " ... ");
    mqtt.unsubscribe(TOPIC_SUBSCRIBE); // Will halt if fails
    Serial.println("OK");
  }
}

/**************************************************************************/
/*!
    @brief  Connect to defined Access Point
*/
/**************************************************************************/
bool connectAP(void)
{
  // Attempt to connect to an AP
  Serial.print("Attempting to connect to: ");
  Serial.println(WLAN_SSID);

  if ( Feather.connect(WLAN_SSID, WLAN_PASS) )
  {
    Serial.println("Connected!");
  }
  else
  {
    Serial.printf("Failed! %s (%d)", Feather.errstr(), Feather.errno());
    Serial.println();
  }
  Serial.println();

  return Feather.connected();
}
This guide was first published on Mar 23, 2016. It was last updated on Mar 23, 2016. This page (AdafruitAIO) was last updated on Apr 28, 2019.