MQTT API¶
How to access the aedifion.io MQTT API.
Why MQTT?¶
MQTT is a lightweight publish/subscribe messaging protocol. Originally designed for machine to machine (M2M) telemetry in low bandwidth environments, MQTT has nowadays become one of the main protocols for (data collection in) Internet of Things (IoT) deployments [1,2].
For simple messaging use cases, MQTT has multiple advantages over HTTP [3] and other protocols:
- Due to its binary encoding and minimal packet overhead, MQTT is 20x faster than HTTP, uses 50x less traffic, and consumes 20% less energy than HTTP according to the direct performance comparison presented in [4].
-
Contrary to HTTP's client/server architecture, MQTT's publish/subscribe pattern decouples data sources from data sinks through a third party, the MQTT broker. According to [5], decoupling means that sources never directly talk to sinks which implies that:
- they do not need to know each other,
- they do not need to run at the same time, and
- they do not require synchronization
All this easily allows building flexible 1-to-many, many-to-1, and many-to-many data pipelines. - MQTT has message filtering built-in, i.e., data sinks can subscribe to arbitrary subsets of the data collected from the sources specified through a hierarchical topic theme [6].
When you are building an application that streams data into or from the aedifion.io platform, MQTT is probably a better choice than the HTTP API.
Part of the aedifion.io platform is an MQTT broker which serves as the single logical point of data ingress to the aedifion.io, e.g., all data collected in the field through the aedifion Edge Devices is ingested to aedifion.io through this MQTT broker and, in turn, can also be subscribed to. The MQTT broker is clustered, i.e., distributed over multiple independent servers, to ensure seamless scalability and high availability.
MQTT Broker¶
The MQTT API is providd by an MQTT broker. To use the MQTT API, you need to connect to this broker with a unique client id using login credentials for authentication and authorization.
Connecting¶
If you are using the aedifion.io cloud platform, the MQTT broker's URL is
mqtt.aedifion.io
If you are using a dedicated aedifion.io platform instance, remember to use the correct subdomain
mqtt.<REALM>.aedifion.io
where <REALM>
is specific to your dedicated platform.
Dedicated platforms and subdomains
In the following and throughtout this documentation, we will use URLs that refer to the aedifion.io cloud platform. If you are using a dedicated platform, remember to use the correct subdomain as explained above.
The MQTT broker accepts connections on two ports:
- Port 8883 accepts plain MQTT, i.e., connections that transport MQTT directly via TLS. This is the standard case and, if in doubt, this port is the right choice.
- Port 9001 accepts websockets connections, i.e., connections that transport the MQTT protocol within the websockets protocol which in turn is transported via TLS. MQTT via websockets is the right choice when you want to send/receive MQTT data directly from a web browser. Read more about MQTT over websockets here and here.
MQTT brokers only accept TLS 1.2 and TLS 1.3 encrypted connections, i.e., all plain TCP connections are rejected. The MQTT broker authenticates itself towards the client using an X.509 certificate issued by Let's Encrypt. Your operating system (OS) will accept this certificate if the root certificates of Let's Encrypt are installed as a trusted root certification authority (CA) in your OS. Don't worry, this is probably the case and you don't have to do anything.
Test your connection
To test the connection to the MQTT broker, run the following command on your command line:
openssl s_client -connect mqtt.aedifion.io:8883 -servername mqtt.aedifion.io
There will be a warning verify error:num=20:unable to get local issuer certificate
at the top, which can be fixed by providing option -CAfile
or -CApath
and pointing to the right locations depending on your OS, e.g., -CAfile /etc/ssl/cert.pem
on Mac OS.
Client Identifiers¶
Clients are identified by a unique client_id
. As per the MQTT 3.1.1 specification (Section 3.1.3.1), client identifiers are between 1 and 23 alphanumeric characters (0-9, a-z, A-Z). Most MQTT brokers support longer client identifiers from the the full range of UTF-8 characters and only characters /
, +
, and #
which have a special meaning in MQTT and are disallowed for security reasons.
It is important to note that there can only be one connection per client_id
per Broker. If two clients connect with the same client_id
the older connection is terminated in favor of the newer. This restriction does not extend to your login credentials (see authentication). You can open multiple connections using the same login credentials as long as you use a different client_id
for each concurrent connection.
Choose a client_id
and avoid special characters. Postfix the client_id
with a random string or integer to ensure it is unique across concurrent connections.
Authentication¶
The MQTT brokers only accept connections from authenticated clients. To authenticate, the MQTT client has to present login credentials (username
and password
) to the MQTT broker within the initial MQTT handshake, i.e., as part of the CONNECT
message.
Client credentials can be obtained with limited and unlimited validity.
- Credentials with unlimited validity are provided only on request by the aedifion staff. Please email us at support@aedifion.io.
- Credentials with limited validity can be created through the aedifion.io HTTP API. Please refer to the corresponding guide for further instructions and details.
Authorization¶
The MQTT broker authorizes clients to subscribe and publish based on topics.
Once connected and authenticated, the client can publish or subscribe to one or multiple topics, but not without authorization. To subscribe, the client needs read access to that topic. To publish, the client needs write access. Note that write access does not imply read access.
Authorization is specified through a list of topics (following exactly MQTT's topic syntax and semantics) where for each topic it is specified whether the user has read and/or write access. Make sure to familiarize yourself with MQTT's topic structure, especially with hierarchy levels and the #
wildcard.
Topic hierarchy¶
All MQTT topics on aedifion.io have a hierarchy that consists of two main parts, i.e., a fixed prefix and a variable postfix.
The prefix has two hierarchies and is assigned by aedifion:
<load-balancing-group>/<project-handle>
- The top level hierarchy, the
load-balancing-group
, is fixed and assigned by aedifion. It serves to separate different customers and projects and ensures that each customer and project is guaranteed separate and sufficient processing and communication resources. - The second level hierarchy, the
project-handle
, is a fixed (human-readable) string assigned by aedifion that uniquely identifies your project. This hierarchy separates different projects on the same load balancing group.
As an aedifion.io customer, you receive authorization to this prefix, i.e., to the topic <load-balancing-group>/<project-handle>/#
, i.e., you can publish and subscribe to "anything below" the project level of the topic hierarchy.
The postfix matching the #
can generally have arbitrary length or structure as long as they are UTF-8 strings.
-
If you've purchased an aedifion Edge Device, e.g., this device collects data from different datapoints on your building network and publishes them to the postfixes
datapoint_1
, ...,datapoint_n
. Via MQTT, you thus have datapoint-level publish/subscribe access to the datapoints of your building. For efficiency reasons, the Edge Device uses short 4 to 12 characters long identifiers generated from the full datapoint names, e.g., the 8-character hash identifier of the datapointmy_very_veeeeeery_long_datapoint_id
is justVD0pZLej
.aedifion's hash identifiers creation
- Build a SHA1 hash out of the UTF-8 encoded datapoint id.
- base62-encode the shortenend hash.
- Cut the first
hash_id_length
characters wherehash_id_length
is configured individually per project (default = 8).
Here's a sample implementation in Python using the pybase62 module.
import base62 import hashlib def base62id(s: str, hash_id_length: int = 8): return base62.encodebytes(hashlib.sha1(s.encode('utf-8')).digest())[:hash_id_length]