One of the crucial aspects of MQTT is the broker. Among other things, the broker manages connected clients, ensuring messages are received from and sent to the correct devices. The broker doesn’t simply forward messages, however. It can also respond to devices being connected and disconnected - an immensely useful feature. I recently updated lightt to leverage two MQTT features:
Last Will and Testament (LWT) for availability updates
Retained messages for persistent state
Here’s an explanation of what I did to get these features working for me, with some examples from Home Assistant and mosquitto. If you want to try out the examples, install mosquitto.
Last Will and Testament (LWT)
Binary devices have two basic states, on or off:
There is a third state, even for binary devices, which is very useful: unavailable:
An unavailable state allows home automation software to prevent commands being sent to a disconnected device. It is also useful for monitoring the health of devices, or as a failsafe. For instance, if an alarm system is powered down, other devices can be alerted to this fact. Google Assistant will also mention if devices are unavailable.
But how can a device tell other devices when it is disconnected? This is where the power of the broker and LWT comes in. When a device connects to a broker, it can specify an LWT topic and payload. The broker receives this information and will publish it when that device is disconnected. Essentially, the device says “I’d like to connect. When I eventually disconnect, publish this message”. The broker takes on the responsibility and publishes the LWT payload on the device’s behalf when it becomes disconnected.
Let’s give this a go in Arduino C++ using PubSubClient:
// Connect to the broker and tell it to publish "offline" to the availability topic when disconnected in the futurechar availabilityTopic[] = "light/desktop/availability";
bool mqttConnected = client.connect(
mqttClientname,
mqttUser,
mqttPassword,
availabilityTopic,
0,
1,
"offline");
if (mqttConnected) {
client.subscribe(commandTopic, 1);
// Publish "online" to the availability topic now to signify connection
client.publish(availabilityTopic, "online", true);
Serial.println("connected");
}
You can play around with this by using mosquitto_sub to investigate messages. Run mosquitto_sub then turn the device on and off. You should see something like this:
The “offline” message is received like magic after the device loses power! The broker has delivered the last will and testament of the client.
Home Assistant can be set up to use this topic. By default, it expects “online” and “offline” as payloads on the availability topic. Here is an example mqtt_template light entry in configuration.yaml:
When a device powers up, what state should it be in? Let’s take a light for example. An easy option would be to have the light turn on to the same colour each time. Or maybe have the light remain off (“black”) to make restarts inconspicuous. The best option is to have the light retain its previous state. There are two main ways to do that:
The light remembers its own last state, perhaps by writing every change to persistent storage and reading this storage on boot.
The light gets its previous command from the broker and executes that command to restore state.
Both approaches have their merits, but I like the second option because it ensures all parts of our setup are working from the ground truth provided by the broker.
MQTT has a feature just for this - retained messages. Any message can be sent as a retained message. This message will be sent to future subscribers to the topic as soon as they subscribe. Only the latest retained message for that topic will be sent. Let’s see it in action using mosquitto_sub and mosquitto_pub.
$ mosquitto_sub -t "light/test" -v -h localhost
Nothing to see here! No messages are being published to this channel so the output is empty. Kill this command and we can do some publishing:
We sent two messages to the test topic, with a key difference: the -r flag in the first command means this message is retained and will be sent to new subscribers. We can check this by subscribing again:
Leveraging the LWT and retain features of MQTT has made me realise just how useful MQTT can be. These features facilitate convenient use cases in home automation software. Previously I thought MQTT’s broker seemed like a redundant middleman. Now it is clear just how powerful this architecture is for transparently managing subscribers and their payloads.