MQTT
MQTT is an IoT friendly messaging protocol for publishing and subscribing to a shared MQTT broker from a wide range of devices.
This tutorial shows you how to connect to an MQTT broker using TCP (or TLS).
Connect
The Toit MQTT client is available from the mqtt
package - in the Toit package registry.
Install the package using the Jaguar:
and use it by importing it into your application with import mqtt
.
MQTT requires every client to have a unique CLIENT_ID
. That ID is sent when connecting to the broker, and identifies a session on the broker.
It is used to reliably transmit packets that require acknowledgements (QoS=1).
import net import mqtt // Include a random number, as we are sharing test.mosquitto.org with other users. CLIENT_ID ::= "my-client-id-$(random)" HOST ::= "test.mosquitto.org" main: network := net.open transport := mqtt.TcpTransport network --host=HOST client := mqtt.Client --transport=transport client.start --client_id=CLIENT_ID // Client is now connected.
Some brokers require the client to provide a username
and password
. These can be passed to the client during the
start
call in an options
object:
options := mqtt.SessionOptions --client_id=CLIENT_ID --username=MY_USERNAME --password=MY_PASSWORD client.start --options=options
See the documentation or examples of the MQTT library for more information.
Publish
Simple sensor applications mainly have one purpose; to send sensor data. When sending data, you simply need to specify which topic to publish to, together with the payload.
A publish function could look similar to the following:
import mqtt import encoding.json TOPIC ::= "my/topic" publish client/mqtt.Client value/float: payload := json.encode { "value": value } client.publish TOPIC payload
Note that the payload must be a byte array. If your data is a string, simply call .to_byte_array
on it.
Subscribe
Subscribing to data requires two pieces of information: the topic (or filter) to subscribe to, and the callback that should be called when a message arrives.
For example:
import mqtt import encoding.json TOPIC ::= "my/topic" subscribe client/mqtt.Client: client.subscribe TOPIC:: | topic/string payload/ByteArray | decoded := json.decode payload print "Received value on '$topic': $(decoded["value"])"
Here, we decode the incoming payload with the JSON decoder. If the data payload should just be interpreted as a
string, you can simply call payload.to_string
instead.
Since MQTT clients can have a session on the server, we could receive packets for previously subscribed topics
as soon as the client connects. If the subscribe
function wasn't called yet, then the callback wouldn't be
invoked for these early messages. To avoid losing packets, the client can also be configured with routes at
construction time:
main: network := net.open transport := mqtt.TcpTransport.tls network --host=HOST --root_certificates=[ certificate_roots.ISRG_ROOT_X1 ] routes := { TOPIC: :: | topic/string payload/ByteArray | decoded := json.decode payload print "Received value on '$topic': $(decoded["value"])" } client := mqtt.Client --transport=transport --routes=routes client.start --client_id=CLIENT_ID // Client is now connected and subscribed to the given routes.
TLS
The TcpTransport
mentioned above can also be used to connect to secure servers. For
that we need root certificatse which are then used to authenticate the server.
Here, we are using the certificate-roots package which can be installed with
In other cases, the certificate might be given by the server and should be pasted into the sources.
Once we have the root certificates, the client's transport can be created as follows:
import mqtt import net import net.x509 import certificate_roots // Include a random number, as we are sharing test.mosquitto.org with other users. CLIENT_ID ::= "my-client-id-$(random)" HOST ::= "test.mosquitto.org" PORT ::= 8886 main: network := net.open transport := mqtt.TcpTransport.tls network --host=HOST --port=PORT --root_certificates=[ certificate_roots.ISRG_ROOT_X1 ] client := mqtt.Client --transport=transport client.start --client_id=CLIENT_ID // Client is now connected.