Publishers and subscribers never meet
Publish and subscribe is a way for programs to share messages without knowing about each other. A publisher sends a message to a topic, a subscriber listens to a topic, and a broker passes each message between them.
This is how one door sensor can tell a phone, a logger and an alarm at once. None of them is wired to it.
By the end of this lesson
Note
I can explain publish and subscribe.
Key words
| Word | What it means | Example |
|---|---|---|
| Publisher | a program that sends messages to a topic | |
| Subscriber | a program that listens to topics | |
| Topic filter | the pattern a subscriber uses to choose topics | home/+/temperature |
| Single-level wildcard | the symbol + that matches exactly one level | |
| Multi-level wildcard | the symbol # that matches every level below |
The cells students fill in are left blank in this preview.
The broker sits between them
A publisher does not know who is listening. A subscriber does not know who is sending. Each of them talks only to the broker.
When a message arrives, the broker looks at every subscription and passes the message to each subscriber whose filter fits the topic. If nobody is listening, the message is simply not delivered.
Publish a retained message of your own
docker exec broker mosquitto_pub -t home/notes/lecture -r -m 'hello from the class'Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Subscribe and read it back
docker exec broker mosquitto_sub -t home/notes/lecture -v -C 1 -W 3Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Your own message comes back the same
The first command prints nothing. -t is the topic, -m is the payload and -r makes the message retained. The topic is one you made up, so nobody else is writing to it.
The second prints exactly home/notes/lecture hello from the class. You were a publisher, then a subscriber, and the broker held the message between.
A topic filter chooses what you hear
A subscriber says which topics it wants with a topic filter. A filter with no symbols matches one topic only.
The symbol + matches exactly one level. So home/+/temperature matches home/kitchen/temperature but not home/temperature. The symbol # matches everything below, and it may only be the last level.
Worked example: which filters match a topic
| Filter | home/kitchen/temperature | home/door/state | garden/soil/moisture |
|---|---|---|---|
| home/# | Yes | Yes | No |
| home/+/temperature | Yes | No | No |
| home/+ | No | No | No |
| # | Yes | Yes | Yes |
| home/door/state | No | Yes | No |
The cells students fill in are left blank in this preview.
Listen to one room, any sensor
docker exec broker mosquitto_sub -t 'home/livingroom/+' -v -C 4 -W 10Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A filter changes which lines you see
This asks for every sensor in the living room. You see lines that start with home/livingroom/temperature or home/livingroom/humidity, each with a whole number. The kitchen and the door never appear, because their topics do not fit.
The order and the numbers depend on when you press Run.
A common mistake
Warning
Many people think a subscriber asks the sensor for a reading. It does not. The sensor publishes when it likes, and the broker passes the message to whoever is subscribed at that moment. That is why a retained message exists: it is how a late subscriber still learns the last value.
Ask for the door state
docker exec broker mosquitto_sub -t home/door/state -v -C 1 -W 5Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A retained message answers a late subscriber
The door sensor marks its messages retained, so this command answers at once with one line: home/door/state and then open or closed. The broker already held the last message.
A topic that is not retained would make you wait until the sensor next publishes. Retained does not mean kept for ever: the next message on the topic replaces it.
Match one level at a time
topic = "home/kitchen/temperature"
pattern = "home/+/temperature"
a = topic.split("/")
b = pattern.split("/")
same = len(a) == len(b)
for i in range(len(b)):
if same and b[i] != "+" and b[i] != a[i]:
same = False
# Change the pattern to home/+/humidity, then press Run.
print(same)