Note that this project is not associated with or endorsed by http://mqtt.org
This document describes an architectural concept for a Smart Home Automation system which ties together heterogeneous hardware using a centralized message bus: MQTT.
Effectively, it just defines a convention for exchanging messages, and a message format.
It's goal is to provide an interoperability layer close to the hardware level. Logic and Visualization are to be implemented at a higher level, on top of the MQTT bus.
+---------------+
| | +----------------------+
| Logic Engine +-------+ +-----+ Hardware Interface A |
| | | | | (e.g. KNX) |
+---------------+ +--+----------+-+ +----------------------+
| |
| MQTT-Broker |
| |
+---------------+ +--+----------+-+ +----------------------+
| | | | | Hardware Interface B |
| Visualization +-------+ +-----+ (e.g. Homematic) |
| | +----------------------+
+---------------+
This convention does make no attempt at abstracting hardware messages into higher level concepts like "Lights" or "Switches". Current home automation hardware and their hardware interfaces have a wide range of different design concepts, ranging from simply addressing devices directly (like many basic RF protocols) over abstracting devices into channels and datapoints (e.g. Homematic) to the link-orientied Group Address concept used by KNX. This abstraction, if required, needs to happen at a higher level, e.g. inside a logic engine.
A MQTT broker (http://en.wikipedia.org/wiki/MQTT) serves as the central message bus. In short, MQTT allows applications to exchange messages under so-called "topics". Applications which are interested in certain topics subscribe to them, and other applications publish messages to them.
MQTT topics are hierarchically structured, much like files and directories in a file system. Example:
toplevelname/function/item...
By convention, in mqtt-smarthome the toplevelname will always refer to a specific instance of a hardware interface or other participent in the system.
The second level function defines a function like status, set etc.
The subsequent levels are defined by the specific interface.
For example, a KNX gateway might reflect the KNX Group Address hierarchy, which might look like
knxgateway1/status/Kitchen/Lights/Front Left
whereas a Homematic interface may represent device/channel names and datapoints:
hm/status/Light Kitchen Front Left/LEVEL
The toplevelname should be configurable so that multiple instances of interfaces can coexist on a single message bus.
Interfaces report states (values from sensors, feedback from actuators) by publishing into the topic.
toplevelname/status/itemname
The retain flag should be set depending on whether the status is a one-shot event (e.g. a keypress) or a measurement or other state (e.g. a temperature). One-shot events should not be retained, whereas states should have retain set.
Visualization UIs and Logic Engines request state changes by publishing the requested new value into the topic
toplevelname/set/itemname
The itemname hierarchy for set should be the same as the one used for the status function tree.
Messages published to this hierarchy should never have the MQTT retain flag set.
Each interface should maintain a topic.
toplevelname/connected
which is an integer enum:
0
- disconnected from MQTT broker1
- connected to MQTT, but disconnected from hardware2
- connected to MQTT and hardware, i.e. fully operational
It should ensure that this is set to 0 using MQTT's Last Will and Testament functionality upon a disconnect.
Interfaces which support active value requests from hardware devices (like KNX or Homematic) may support a hierarchy
toplevelname/get/itemname
A write of any value to that hierarchy should trigger an active read operation of the given itemname. The result of the read should be published by the interface as a status update.
Messages published to this hierarchy should never have the MQTT retain flag set.
Interfaces may support a command scheme which may not be representable by the normal item hierarchy. In this case, the interface may listen to
toplevelname/command
to receive such commands.
Messages published to this hierarchy should never have the MQTT retain flag set.
MQTT supports various QoS (Quality of Service) levels for messages and connections:
0
- no guaranteed delivery, no duplicates possible1
- guaranteed delivery, duplicates possible2
- guaranteed delivery, no duplicates possible
In the context of this proposal, it is recommended that QoS 1 is best avoided due to the chance that messages may be delivered multiple times.
It should be assumed that duplicated messages in the set, get and command hierarchies may cause unwanted repeated hardware interaction, and that duplicated messages in the status hierarchy may trigger unwanted repeated events in a logic layer.
The message format for status reports may either be a simple value or a JSON encoded object which contains the simple value and possible additional information.
The message format for set operations is always a simple value.
The actual type of simple value depends on the underlying hardware. It may be a boolean, a integer or floating point number, or a string.
If the status message is a JSON encoded object, the object will always have at least the field val, which holds aforementioned simple value.
Additional possible fields:
ts
- the timestamp when the value was obtained. Milliseconds since Epoch.lc
- the timestamp when the value last changed. Milliseconds since Epoch.
Example:
{
"val": 17.9,
"ts": 1421792677000,
"lc": 1421792677000
}
Interfaces may include additional fields in the object. Those fields always should be prefixed with a mnemonic identifier denoting the interface. For example, a KNX interface may include a field "knx_src_addr" which holds the originating bus address of a KNX write message.
Feedback is welcome. Feel free to open an issue or a pull request on GitHub.
The project logo is based in part on work by http://brsev.deviantart.com/ licensed as Creative Commons Attribution Non-commercial (by-nc)
- V0.1 - 2015-01-05 - owagner
- first draft
- V0.2 - 2015-01-11 - owagner
- interfaces may define additional topics
- recommendation that interfaces should have a configurable topic prefix
- expanded architecture rationale
- V0.3 - 2015-01-12 - owagner
- clarify that the "connected" topic is also supposed to be a JSON object
- V0.4 - 2015-01-20 - owagner
- major revamp:
- split topic hierarchies into status/set subhierarchies, thereby getting rid of the "ack" flag
- messages may now be simple values as well as JSON encoded objects
- defined "ts" and "lc" timestamps
- extended "connected" into an enum to differentiate between a running interface with and without active hardware connection
- major revamp:
- V0.5 - 2015-01-21 - owagner
- clarified retain and QoS recommendations (thanks to bartbes)