Overview -------- 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. Message Bus ----------- 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. ## Topic Hierarchy ## 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. ### Status reports ### 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. ### Change/Action requests ### 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. ### Connected status ### Each interface should maintain a topic toplevelname/connected which is an integer enum: * 0 - disconnected from MQTT broker * 1 - connected to MQTT, but disconnected from hardware * 2 - 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. #### Active get #### 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. #### Command channel #### 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. ### QoS recommendations ### MQTT supports various QoS (Quality of Service) levels for messages and connections: * 0 - no guaranteed delivery, no duplicates possible * 1 - guaranteed delivery, *duplicates possible* * 2 - 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. Message format -------------- 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.