In our last post we looked at a Swift MQTT client which published information to a HiveMQ broker. Now let’s turn our attention to writing an MQTT client that subscribes to a topic.
Again, we’ll be using MQTT, code that aims to provide a solid MQTT client library implementation in Swift. If you haven’t yet read the tutorial on building an MQTT publisher with it, I suggest you do so before proceeding!
There are two basic components to writing an MQTT client that subscribes to a topic:
- subscribing to a topic
- handling a published message from the broker
Ignoring the boilerplate connection logic for a moment, let’s look at subscribing:
1 2 3 |
_ = nc.addObserverForName("ConnectedNotification", object:nil, queue:nil) {_ in _ = client.subscribe(topic:"/\(hostname)/cpu/temperature/value") } |
There’s nothing earth shattering here: upon receiving a ConnectedNotification
a call is made to subscribe to the topic /hostname/cpu/temperature/value
(where hostname is obtained from the OS). Now when the broker receives a message published to this topic it will broadcast it to our client. This is the pub-sub pattern in action.
This Transmission is Coming To You
To receive an MQTT message we need to handle the MQTTDelegate
method func mqtt(mqtt: MQTT, didReceiveMessage message: MQTTMessage, id: UInt16 )
. This can be readily accomplished using an NSNotification
with accompanying userInfo
:
1 2 3 4 5 6 7 |
func mqtt(mqtt: MQTT, didReceiveMessage message: MQTTMessage, id: UInt16 ) { let userInfo:[NSObject:AnyObject] = ["message" as NSString:message] NSNotificationCenter.defaultCenter().postNotificationName("MessageNotification", object:nil, userInfo:userInfo) } |
Unfortunately for us much the userInfo
dictionary remains grounded in using NSObject
s as keys, so care must taken to cast String
as an NSString
when assembling.
In the main.swift
implementation we listen for a MessageNotification
:
1 2 3 4 5 6 7 8 |
_ = nc.addObserverForName("MessageNotification", object:nil, queue:nil){ notification in if let userInfo = notification.userInfo, let message = userInfo["message" as NSString] as? MQTTMessage { if let string = message.string { print("Received \(string) for topic \(message.topic)") } } } |
For details on the MQTTMessage
class, see the source, but we can gather from the above that two properties are of interest here:
topic:String
– the topic to which the message was deliveredstring:String?
– the message contents, if any, delivered as aString
Get the Code
MQTTSub is an example implementation of an MQTT client that subscribes to our CPU temperature topic. Obtain it and compile with:
# git clone https://github.com/iachievedit/MQTTSub # cd MQTTSub # swift build # .build/debug/MQTTSub
You will, of course, want to be running the publishing client as well:
# git clone https://github.com/iachievedit/PubSysTemp # cd PubSysTemp # swift build # .build/debug/PubSysTemp
If your publishing client is running, you’ll see something like:
2016-06-13 02:55:43 +0000 - INFO - Connecting to broker 2016-06-13 02:55:43 +0000 - INFO - MQTT client has connected to broker.hivemq.com:1883 2016-06-13 02:55:43 +0000 - INFO - Subscribe to topic 2016-06-13 02:55:43 +0000 - INFO - didConnectAck 2016-06-13 02:55:43 +0000 - INFO - didSubscribeTopic /darthvader/cpu/temperature/value 2016-06-13 02:55:44 +0000 - INFO - Received 33.0 for topic /darthvader/cpu/temperature/value
If you want to have fun, try stress testing your system while running the publisher and subscriber. After stress -c 8
was started up:
PubSysTemp
2016-06-13 03:04:55 +0000 - INFO - Published temperature to 34.0 2016-06-13 03:05:05 +0000 - INFO - Published temperature to 37.0 2016-06-13 03:05:15 +0000 - INFO - Published temperature to 42.0 2016-06-13 03:05:25 +0000 - INFO - Published temperature to 45.0 2016-06-13 03:05:35 +0000 - INFO - Published temperature to 47.0
MQTTSub
2016-06-13 03:04:55 +0000 - INFO - Received 34.0 for topic /darthvader/cpu/temperature/value 2016-06-13 03:05:05 +0000 - INFO - Received 37.0 for topic /darthvader/cpu/temperature/value 2016-06-13 03:05:15 +0000 - INFO - Received 42.0 for topic /darthvader/cpu/temperature/value 2016-06-13 03:05:25 +0000 - INFO - Received 45.0 for topic /darthvader/cpu/temperature/value 2016-06-13 03:05:35 +0000 - INFO - Received 47.0 for topic /darthvader/cpu/temperature/value
What’s Next?
If you peruse the MQTT library you’ll notice it is lacking SSL support. That’s what’s next! In addition, we’ll be looking at writing additional MQTT tutorials that explore constructing topic hierarchies, using MQTT with real-world sensors, home automation devices, and more.