Raspberry Pi

MQTT Topic Trees

This document describes a generic approach to handling topics in our MQTT applications. There is of course no right or wrong approach to designing topics: this document doesn't have an ambition to describe a 'standard'. What it does strive to achieve is to outline how we typically want to setup topic trees, in a more or less unified structure.

An application designer who sees a need to change the structure is welcome to do so - as long as the structure is well documented.

We have gone through the standard steps of over-complex and over-simplified structures and have settled on a relatively straightforward one.

Note

For MQTT solutions on our site, we will roughly follow this guide and refer to it from within our solutions.

Designing topic trees

Here is a list of reminders to help you design your ultimate topic tree.

  • Remember how items within the topic tree will be read: reading deeply nested topics is a hurdle, using too many wild cards a hurdle as well. Apart from trying to use good naming, try to make the meaning short
    • Don't forget to see how allowed wildcards ('+', '#') are going to be applied on consumer side
  • Follow the standard tips:
    • No special characters are recommended for topic names
    • No spaces within topic name allowed
    • Clear and short words are used to identify an entity in the topic tree
    • Identify the type of device, location, feature etc. as needed, but bundle attributes in the message content. For instance: sending a temperature should end up in a 'temperature branch' somewhere in your topic tree, but attributes such as 'Celsius' or 'Fahrenheit' are bundled in the message, instead of sending into 2 message topics
    • Message payload can be either a simple string or a JSON object
  • Avoid using the '#' wildcard at the root. This is always a bad pattern
  • Another anti-pattern: using the MQTT structure as a messaging solution (i.e. one topic contains all messagess with different meaning) is not a good idea. Try to add a structure which at least separates the same type of data into one topic and don't mix up different messages into one topic
  • Use the topic tree suggested in this document if it fits your needs, or simply design your own. The only requirement: make sure your design is well documented

Generic Topic Structure

The general topic structure used today is the following:

device-category/device-id/payload-context/payload-differentiator

Device-Category

We try to separate our message flow by identifying the root category into logical sections. A device category should separate message flows by logical groups; those groups can be really anything which fits your application requirements. For example:

  • my factory floors
  • my machines in the field
  • my house
  • autonomous devices (vs. RC devices)
  • simulators
  • etc.

The rule of thumb: the differentiatior of 'Device-category' has to be abstract enough to provide one root only and specific enough to separate different application uses

Important: make sure you think through the design. For instance the above mentioned category simulators really depends on context. In a scenario, where you maybe design a solution and have not acquired the right hardware, or if you stress-test an application, it is a good idea to keep it as a 'device-category'. However, in a scenario, where you debug an existing application and mock some data, it stops making sense: in such a case the simulator identification can become a part of the 'device-id' described below, if used at all.

Device-id

The device ID is the separator of each sending device in the application. The idea is to separate (rather early) each unique instance of a device from others. In programming parlance: while 'Device-Category' identifies the 'Object' (i.e. template used), the 'Device-ID' identifies the 'instance' of an object.

Device IDs can take any form required by the application. Here are some more typical ones:

  • Serial # of device
  • Device Name and sequence number (i.e. 'CNC01', 'CNC02')
  • etc.

Payload Context

This is the context field. Here we differentiate between generic and pre-defined context fields of a measurement or type of value being sent.

While all the above and below topic fields are basically up to the designer to structure based on application need, we try to keep the context name as standard as possible.

Here are the context names used and recommended:

  • temperature
  • pressure
  • location
  • heartbeat
  • etc.

Payload Differentiator

This field is optional and depends on application / or part of application. It is used for differentiating measurements or messages of the same type. For instance you might want to use 'Front' and 'Back' for adding a level of mesurement for a given context.

You can easily skip this part

Extra levels

It is up to you as developer to add more subtopics to the topic tree. This is neither recommended, nor dicouraged.