MQTT API

MQTT, or message queue telemetry transport, is a protocol for device communication that Adafruit IO supports.  Using a MQTT library or client you can publish and subscribe to a feed to send and receive feed data.

If you aren't familiar with MQTT check out this introduction from the HiveMQ blog.  All of the subsequent posts in the MQTT essentials series are great and worth reading too.

To use the MQTT API that Adafruit IO exposes you'll need a MQTT client library.  For Python, Node.js, and Arduino you can use Adafruit's IO client libraries as they include support for MQTT (see the client libraries section).  For other languages or platforms look for a MQTT library that ideally supports the MQTT 3.1.1 protocol.

Connection Details

You will want to use the following details to connect a MQTT client to Adafruit IO:

  • Host: io.adafruit.com
  • Port: 1883 or 8883 (for SSL encrypted connection)
  • Username: your Adafruit account username (see the accounts.adafruit.com page here to find yours)
  • Password: your Adafruit IO key (click the AIO Key button on a dashboard to find the key)

We strongly recommend using SSL if your MQTT client allows it.

If the MQTT library requires that you set a client ID then use a unique value like a random GUID.  Most MQTT libraries handle setting the client ID to a random value automatically though.

Topics

Adafruit IO's MQTT API exposes feed data using special topics.  You can publish a new value for a feed to its topic, or you can subscribe to a feed's topic to be notified when the feed has a new value.  Any one of the following topic forms is valid for a feed:

  • (username)/feeds/(feed name or key)
  • (username)/f/(feed name or key)

Where (username) is your Adafruit IO username (the same as specified when connecting to the MQTT server) and (feed name or key) is the feed's name or key.  The smaller '/f/' path is provided as a convenience for small embedded clients that need to save memory.

Check out our guide to Feed Naming for the full details.

For example if your username is mosfet and you're accessing a feed called Photocell One (which has a Key of photocell-one) you can use any of these paths:

  • mosfet/feeds/Photocell One
  • mosfet/f/Photocell One
  • mosfet/feeds/photocell-one
  • mosfet/f/photocell-one

To append a new value to a feed perform a MQTT publish against the feed path and provide the new feed value as the payload of the request.

To be notified of a change in a feed perform a MQTT subscribe against the feed path.  When a new value is added to the feed then the Adafruit IO MQTT server will send a notification with the new feed value in the payload.

You can also subscribe to the parent 'feeds' path to be notified when any owned feed changes using MQTT's # wildcard character.  For example the mosfet user could subscribe to either:

  • mosfet/feeds/#
  • mosfet/f/#

Once subscribed to the path above any change to a feed owned by mosfet will be sent to the MQTT client.  The topic will specify the feed that was updated, and the payload will have the new value.

Be aware the MQTT server sends feed updates on all possible paths for a specific feed. For example, subscribing to mosfet/f/# and publishing to mosfet/f/photocell-one would produce messages from: mosfet/f/photocell-one, mosfet/f/photocell-one/json, and mosfet/f/photocell-one/csv; each referring to the same updated value.  To reduce noise, make sure to grab the specific topic of the feed / format you're interested in and change your subscription to that.

PLEASE NOTE: as we adjust which identifiers we use for Feeds internally, the feed updates you receive when using a wildcard will include but may not be limited to the ones shown above.

If you'd like to avoid the formatted feeds ("/json" and "/csv" topics) but still see all the feeds you're publishing to, you can use MQTT's + wildcard in place of #. In this case, subscribing to mosfet/f/+ would produce output on mosfet/f/photocell-one, but not mosfet/f/photocell-one/json.

Publish QoS Levels

One feature of MQTT is the ability to specify a QoS, or quality of service, level when publishing feed data.  This allows an application to confirm that its data has been sucessfully published.  If you aren't familiar with MQTT QoS levels be sure to read this great blog post explaining their meaning.

For publishing feed values the Adafruit IO MQTT API supports QoS level 0 (at most once) and 1 (at least once) only.  QoS level 2 (exactly once) is not currently supported.

Rate Limit

Adafruit IO's MQTT server imposes a rate limit to prevent excessive load on the service.  If a user performs too many publish actions in a short period of time then some of the publish requests might be rejected.  The current rate limit is at most 1 request per second (or 60 requests within 60 seconds).

If you exceed this limit, a notice will be sent to the (username)/throttle topic. You can subscribe to the topic if you wish to know when the Adafruit IO rate limit has been exceeded for your user account.

This limit applies to all connections so if you have multiple devices or clients publishing data be sure to delay their updates enough that the total rate is below 2 requests/second.

Data Format

There are a few ways to send data to our MQTT API if you're writing your own client library.

The simplest way to send values to an IO Feed topic is to just send the value. For example, a temperature sensor is going to produce numeric values like 22.587. If you're sending to mosfet/feeds/photocell-one you can use the raw number or a string. That means either 22.587 or "22.587" will be accepted as a numeric value. Adafruit IO does its best to treat data as numeric values so that we can show you your data as a chart on an Adafruit IO dashboard and through our Charting API.

Data with Location

To tag your data with a location value, you'll either need to wrap it in a JSON object first or send it to the special /csv formatted MQTT topic.

Sending JSON

JSON can be sent to either the base topic or the /json topic-- for example, mosfet/feeds/photocell-one or mosfet/feeds/photocell-one/json. The proper format for location tagged JSON data is:

{
  "value": 22.587, 
  "lat": 38.1123,
  "lon": -91.2325, 
  "ele": 112
}

Specifically, JSON objects must include a "value" key, and may include "lat", "lon", and "ele" keys. 

Sending CSV

Alternatively, you can send location tagged data to /csv topics. In this example that would be the topic mosfet/feeds/photocell-one/csv instead of mosfet/feeds/photocell-one. Both store data in the same feed. The format IO expects for location tagged CSV data is VALUE, LATITUDE, LONGITUDE, ELEVATION.

With the example data shown before, that means you could publish the string "22.587,38.1123,-91.2325,112" to mosfet/feeds/photocell-one/csv. to store the value "22.587" in the location latitude: 38.1123, longitude: -91.2325, elevation: 112.

Examples

Using a simple Ruby MQTT library and the data shown, all these examples publish the same data to the same feed:

# first you'll need https://github.com/njh/ruby-mqtt
require 'mqtt'

username = 'test_username'
key      = 'not-a-real-key'
url      = "mqtts://#{ username }:#{ key }@io.adafruit.com"

mqtt_client = MQTT::Client.connect(url, 8883)

# simplest thing that could possibly work
mqtt_client.publish('test_username/feeds/example', 22.587)

# sending numbers as strings is fine, IO stores all data internally
# as strings anyways
mqtt_client.publish('test_username/feeds/example', '22.587')

# CSV formatted, no location
mqtt_client.publish('test_username/feeds/example/csv', '22.587')

# CSV formatted, with location
mqtt_client.publish('test_username/feeds/example/csv', 
                    '22.587,38.1123,-91.2325,112')

# JSON formatted, no location 
mqtt_client.publish('test_username/feeds/example', '{"value":22.587}')
mqtt_client.publish('test_username/feeds/example/json', '{"value":22.587}')

# JSON formatted, with location
mqtt_client.publish('test_username/feeds/example', 
  '{"value":22.587,"lat":38.1123,"lon":-91.2325,"ele":112}')
mqtt_client.publish('test_username/feeds/example/json',
  '{"value":22.587,"lat":38.1123,"lon":-91.2325,"ele":112}')
Last updated on 2017-09-08 at 12.34.11 PM Published on 2015-01-22 at 02.19.14 PM