MQTT with AWS IoT Core
AWS IoT Core is a managed MQTT broker. It is designed for large scale IoT deployments and supports many advanced features.
Prerequisites
We assume that you have set up your development environment as described in the IDE tutorial.
We also assume that you have flashed your device with Jaguar and that you are familiar with running Toit programs on it. If not, have a look at the Hello world tutorial.
While not necessary, we recommend to do the MQTT tutorial first.
Note that you can do this tutorial without a device. In that case,
you need to use the -d host
option whenever you invoke
jag run
. The program will then run on your computer instead of on
a device.
Packages
The MQTT functionality is not part of the core libraries and must be imported as a package. See the packages tutorial for details.
We are using the mqtt package. To install it, run the following command:
When connecting to TLS secured services we will also use the certificate-roots package:
AWS IoT Core
Amazon has several tutorials on how to get started with their service. For example, see the Getting started guide.
We will not repeat all the steps here, but only give a brief overview.
- Create an AWS account, and sign in.
- Search for the IoT Core service.
- On the left click on "Connect one device".
This will start a wizard that will guide you through the process of creating a device and a certificate.
As instructed, make sure that you can ping your AWS broker. The URL
is shown in the wizard. It should be something like
<your_id>.iot.<your_region>.amazonaws.com
. Remember this URL,
we will need it later.
Select "Create a new thing" and give it a name.
The next screen asks you for the platform operating system and Device SDK. We are not using any of the SDKs, so you can keep the default settings.
Download the connection kit on the next page. This zip file contains the certificate and private key for your device. Unzip it and save the following files into your project directory:
<name>.cert.pem
<name>.private.key
<name>-Policy
<name>-public.key
Strictly speaking, we only need the certificate and private key, but these files aren't big, and for completeness sake we also save the policy and public key.
Code
AWS IoT Core uses TLS with client certificates to authenticate devices. This requires a few more steps than usual to establish a connection.
Create a new file aws.toit
in your project directory, and watch it
with Jaguar.
Add the following code to the file:
import certificate_roots import net import net.x509 import mqtt import mqtt.transport as mqtt import tls HOST ::= "<YOUR AMAZON HOST>" PORT ::= 8883 ROOT_CERTIFICATE ::= certificate_roots.AMAZON_ROOT_CA_1 CLIENT_ID ::= "sdk-nodejs-toit" TOPIC ::= "sdk/test/js" CLIENT_CERTIFICATE_DER ::= """ -----BEGIN CERTIFICATE----- <YOUR CERTIFICATE> -----END CERTIFICATE----- """ CLIENT_KEY_DER ::= """ -----BEGIN RSA PRIVATE KEY----- <YOUR KEY> -----END RSA PRIVATE KEY----- """
Here the HOST
is the URL of your AWS broker. If you forgot it, you
can find it in the "Settings" tab of the IoT Core console.
The CLIENT_ID
and TOPIC
are not arbitrary strings. They must
comply with the policy restrictions for this device. These can
be found in the <name>-Policy
file you downloaded earlier. If
you used the "Connect" wizard, it should, for example, have
the following restrictions for the "iot:Connect"
action:
"arn:aws:iot:eu-west-1:915358716417:client/sdk-java", "arn:aws:iot:eu-west-1:915358716417:client/basicPubSub", "arn:aws:iot:eu-west-1:915358716417:client/sdk-nodejs-*"
The client ID, thus must be either sdk-java
, basicPubSub
, or
sdk-nodejs-*
, where *
is a wildcard. The chosen
sdk-nodejs-toit
is thus a valid client ID.
Any other client ID will be rejected by the broker, and the connection will be cut (leading to an infinite "Attempting to (re)connect" loop).
Similarly, publishing to a topic that is not allowed by the policy will also lead to a disconnect.
The CLIENT_CERTIFICATE_DER
and CLIENT_KEY_DER
are the certificate
and private key that you downloaded earlier. You can copy and paste
them into the file.
Creating the transport
As mentioned above, AWS IoT Core uses TLS with client certificates to authenticate devices. Add the following function that creates an MQTT transport with the correct settings:
create_aws_transport network/net.Interface -> mqtt.Transport: parsed := x509.Certificate.parse CLIENT_CERTIFICATE_DER client_certificate := tls.Certificate parsed CLIENT_KEY_DER return mqtt.TcpTransport.tls network --host=HOST --port=PORT --root_certificates=[ROOT_CERTIFICATE] --certificate=client_certificate
This function accepts a network interface and returns an MQTT transport. It parses the certificate and generates a TLS certificate object from it, and then creates a TLS transport with the appropriate settings.
Connecting to the broker
We can now connect to the broker. Add the following code to the main
function:
main: network := net.open transport := create_aws_transport network client := mqtt.Client --transport=transport options := mqtt.SessionOptions --client_id=CLIENT_ID client.start --options=options client.publish TOPIC "hello".to_byte_array client.close network.close
If you still have the AWS IoT Core console open, you should see the message appear in the wizard.
It is not good practice to hard-code credentials in your program. See the secrets tutorial for details on how to handle secrets in Toit projects.
Summary
In this tutorial we have seen how to connect to AWS IoT Core using
TLS with client certificates. We have also seen how to use the
mqtt
package to publish a message to a topic.
AWS IoT Core supports many more features, such as device shadows, rules, and jobs. See the AWS IoT Core documentation for more details.