AWS IoT
The Amazon Web Services Internet-of-Things (AWS IoT) library enables applications to connect to, and exchange messages with the AWS IoT Core service. The library supports the following technologies:
TLS secured MQTT transmission protocol
Firmware-Over-The-Air (FOTA)
Setup and configuration
To connect a device to AWS IOT Core, complete the following steps:
Setting up AWS and configuring permissions
The initial AWS account setup required for using AWS IoT Core is described in Set up your AWS account.
For development purposes, the AWS managed policies AWSIoTConfigAccess
and AWSIoTDataAccess
provide sufficient permissions to manage AWS IoT.
If you want to use AWS FOTA, the AmazonS3FullAccess
policy can be used to obtain access to AWS S3.
Note
These policies provide a large number of permissions to the user. Though this can be acceptable for development purposes, you should operate on a least-privilege principle whenever possible.
To complete the steps described in this document, make sure that the following prerequisites are met:
Install AWS Command Line Interface on your system and login as a user with appropriate permissions.
To use the
nrfcredstore
tool, the dependencies in thenrf/scripts/requirements-extra.txt
file must be installed.
Generating and provisioning certificates
Things in AWS IoT are typically authenticated using device certificates. There are multiple ways to generate and register these certificates:
The device key pair and certificate are generated by AWS and downloaded onto the device.
The device generates the key pair and a Certificate Signing Request (CSR). This request is uploaded to AWS to obtain a device certificate and is used to generate a self-signed device certificate.
Note
Generating a key pair on device requires an nRF91 Series device. If you are using an nRF9160 DK, modem version v1.3.x or later is required.
Important
Program the Cellular: AT Client sample to your device before following this guide.
Complete the following steps to generate a key pair and CSR on the modem, which is then used to obtain a device certificate signed by AWS:
Obtain a list of installed keys using the following command:
nrfcredstore <serial port> list
where
<serial port>
is the serial port of your device.Select a security tag that is not yet in use. This security tag must match the value set in the
CONFIG_MQTT_HELPER_SEC_TAG
Kconfig option.Generate a key pair and obtain a CSR using the following command:
nrfcredstore <serial port> generate <sec tag> device_cert.csr.der
where
<serial port>
is the serial port of your device and<sec tag>
is the previously chosen unused security tag.Convert the CSR from DER format to PEM format using the following command:
openssl req -inform DER -in device_cert.csr.der -outform PEM -out device_cert.csr.pem
Obtain a signed certificate using the following command:
aws iot create-certificate-from-csr --certificate-signing-request file://device_cert.csr.pem --certificate-pem-outfile device_cert.pem --set-as-active --no-cli-pager --query certificateArn
Take note of the certificate ARN, as it will be required later.
Provision the certificate using the following command:
nrfcredstore <serial port> write <sec tag> CLIENT_CERT device_cert.pem
where
<serial port>
is the serial port of your device and<sec tag>
is the previously chosen unused security tag.Download the Amazon Root CA 1 PEM file.
Provision the certificate using the following command:
nrfcredstore <serial port> write <sec tag> ROOT_CA_CERT AmazonRootCA1.pem
where
<serial port>
is the serial port of your device and<sec tag>
is the previously chosen unused security tag.
Warning
This option is not recommended for production scenarios, since the private key leaves the device.
Important
Program the Cellular: AT Client sample to your device before following this guide.
To obtain a key pair and certificate generated by AWS, and to provision them to the modem, complete the following steps:
Generate the key pair and certificate using the following command:
aws iot create-keys-and-certificate --set-as-active --certificate-pem-outfile device_cert.pem --public-key-outfile pub_key.pem --private-key-outfile priv_key.pem --no-cli-pager --query certificateArn
Take note of the certificate ARN, as it will be required later.
Obtain a list of installed keys using the following command:
nrfcredstore <serial port> list
where
<serial port>
corresponds to the serial port of your device.Select a security tag that is not yet in use. This security tag must match the value set in
CONFIG_MQTT_HELPER_SEC_TAG
Kconfig option.Provision the client certificate using the following command:
nrfcredstore <serial port> write <sec tag> CLIENT_CERT device_cert.pem
where
<serial port>
is the serial port of your device and<sec tag>
is the previously chosen unused security tag.Provision the client key using the following command:
nrfcredstore <serial port> write <sec tag> CLIENT_KEY priv_key.pem
where
<serial port>
is the serial port of your device and<sec tag>
is the previously chosen unused security tag.Download the Amazon Root CA 1 PEM file.
Provision the certificate using the following command:
nrfcredstore <serial port> write <sec tag> ROOT_CA_CERT AmazonRootCA1.pem
where
<serial port>
is the serial port of your device and<sec tag>
is the previously chosen unused security tag.
To obtain a key pair and certificate generated by AWS, complete the following steps:
Generate the key pair and certificate using the following command:
aws iot create-keys-and-certificate --set-as-active --certificate-pem-outfile client-cert.pem --public-key-outfile public-key.pem --private-key-outfile private-key.pem --no-cli-pager --query certificateArn
Take note of the certificate ARN, as it will be required later.
Download the Amazon Root CA 1 PEM file as
ca-cert.pem
.Place the PEM files into the folder path specified by the
CONFIG_MQTT_HELPER_CERTIFICATES_FOLDER
option, default is<app_src_dir>/certs/
. Ensure that theCONFIG_MQTT_HELPER_PROVISION_CERTIFICATES
option is set.If the files are placed correctly, the MQTT helper library finds the certificates and provisions them to the Mbed TLS stack when connecting to AWS IoT.
Creating a policy
AWS IoT Core policies determine which permissions a Thing has and are required to connect to the AWS IoT data plane. To create a policy, complete these steps:
Create a file
policy.json
with the following content:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "iot:*", "Resource": "*" } ] }
Note
This policy example is only intended for development environments. Make sure to update this to a more restrictive policy before you go into production. For more information, refer to the example policies listed in AWS IoT Core policy examples and Security best practices in AWS IoT Core.
Create the policy using the following command:
aws iot create-policy --policy-name my-policy --policy-document file://policy.json
Attach the policy to the previously registered certificate using the following command:
aws iot attach-policy --target <certificate arn> --policy-name my-policy
where
<certificate arn>
is the ARN of the previously generated device certificate.
Creating a Thing
Create a Thing in AWS IoT core by completing the following steps:
Create a Thing using the following command:
aws iot create-thing --thing-name <thing name>
where
<thing name>
is the desired name for the Thing, for example,my-thing
.Attach the certificate to the Thing using the following command:
aws iot attach-thing-principal --principal <certificate arn> --thing-name <thing name>
where
<certificate arn>
is the ARN of the previously generated device certificate and<thing name>
is the previously chosen name of the Thing.
Configuring the library
Complete the following steps to set the required library options:
Obtain the AWS IoT broker endpoint using the following command:
aws iot describe-endpoint --endpoint-type iot:Data-ATS
Set the
CONFIG_AWS_IOT_BROKER_HOST_NAME
Kconfig option to the obtained endpoint value. For information on how to set this value at runtime, refer to Setting the AWS host name at runtime.Set the
CONFIG_AWS_IOT_CLIENT_ID_STATIC
Kconfig option to the name of the Thing created earlier. For information on how to set this value at runtime, refer to Setting client ID at run-time.Set the
CONFIG_MQTT_HELPER_SEC_TAG
to the security tag for which the key and certificate were provisioned earlier.
Optional library options
To subscribe to the various AWS IoT Device Shadow Topics , set the following options:
Other options:
MQTT helper library specific options:
Note
If you are using a longer client ID that is either set by the option CONFIG_AWS_IOT_CLIENT_ID_STATIC
or passed in during connect, it might be required to increase the value of the option CONFIG_AWS_IOT_CLIENT_ID_MAX_LEN
to reserve enough space for the client ID string.
Usage
The AWS IoT sample showcases the use of this library and can be used to verify a connection to AWS IoT. To configure and run the sample, complete the steps described in Setup and Building and running.
Initializing the library
The library is initialized by calling the aws_iot_init()
function.
If this API call fails, the application must not make any other API calls to the library.
Connecting to the AWS IoT MQTT broker
After the initialization, the aws_iot_connect()
function must be called to connect to the AWS IoT broker.
If this API call fails, the application must retry the connection by calling aws_iot_connect()
again.
Note
The connection attempt can fail due to several reasons related to the network. Due to this its recommended to implement a routine that tries to reconnect the device upon a disconnect.
During an attempt to connect to the AWS IoT broker, the library tries to establish a connection using a TLS handshake, which usually spans a few seconds.
When the library has established a connection and subscribed to all the configured and passed-in topics, it will propagate the AWS_IOT_EVT_CONNECTED
event to signify that the library is connected and ready to be used.
Subscribing to non-AWS specific topics
To subscribe to non-AWS specific topics, pass a list containing the topics using the aws_iot_application_topics_set()
function before calling the aws_iot_connect()
function.
The following code example shows how to subscribe to non-AWS specific topics:
#define CUSTOM_TOPIC_1 "my-custom-topic/example"
#define CUSTOM_TOPIC_2 "my-custom-topic/example2"
static const struct mqtt_topic topic_list[] = {
{
.topic.utf8 = MY_CUSTOM_TOPIC_1,
.topic.size = strlen(MY_CUSTOM_TOPIC_1),
.qos = MQTT_QOS_1_AT_LEAST_ONCE,
},
{
.topic.utf8 = MY_CUSTOM_TOPIC_2,
.topic.size = strlen(MY_CUSTOM_TOPIC_2),
.qos = MQTT_QOS_1_AT_LEAST_ONCE,
}
};
err = aws_iot_application_topics_set(topic_list, ARRAY_SIZE(topic_list));
if (err) {
LOG_ERR("aws_iot_application_topics_set, error: %d", err);
FATAL_ERROR();
return err;
}
Publishing to non-AWS specific topics
To publish to a non-AWS specific topic, complete the following steps:
Populate a
aws_iot_topic_data
with the custom topics that you want to publish to. It is not necessary to set the topic type when populating theaws_iot_topic_data
structure. This type is reserved for AWS IoT shadow topics.Pass in the entry that corresponds to the topic that the payload is to be published to in the message structure
aws_iot_data
. This structure is then passed into theaws_iot_send()
function.
The following code example shows how to publish to non-AWS specific topics:
#define MY_CUSTOM_TOPIC_1 "my-custom-topic/example"
#define MY_CUSTOM_TOPIC_1_IDX 0
static struct aws_iot_topic_data pub_topics[1] = {
[MY_CUSTOM_TOPIC_1_IDX].str = MY_CUSTOM_TOPIC_1,
[MY_CUSTOM_TOPIC_1_IDX].len = strlen(MY_CUSTOM_TOPIC_1),
};
struct aws_iot_data msg = {
/* Pointer to payload */
.ptr = buf,
/* Length of payload */
.len = len,
/* Message ID , if not set it will be provided by the AWS IoT library */
.message_id = id,
/* Quality of Service level */
.qos = MQTT_QOS_0_AT_MOST_ONCE,
/* "my-custom-topic/example" */
.topic = pub_topics[MY_CUSTOM_TOPIC_1_IDX]
};
err = aws_iot_send(&msg);
if (err) {
LOG_ERR("aws_iot_send, error: %d", err);
return err;
}
Setting client ID at run-time
The library supports passing in the client ID at runtime.
To use this feature, set the client_id
entry in the aws_iot_config
structure that is passed in the aws_iot_connect()
function when connecting.
The client_id
entry must be a null-terminated string.
Setting the AWS host name at runtime
The library supports passing in the endpoint URL at runtime.
To use this feature, set the host_name
entry in the aws_iot_config
structure that is passed in the aws_iot_connect()
function when connecting.
The client_id
entry must be a null-terminated string.
Testing and debugging
For general information about testing and debugging, see Testing and optimization.
Topic monitoring
To observe incoming messages, navigate to the AWS IoT console and click MQTT test client. Subscribe to the topic that you want to monitor, or use the wild card token # to monitor all topics.
Troubleshooting
For issues related to the library and nRF Connect SDK in general, refer to Known issues.
If you are experiencing unexpected disconnects from AWS IoT, try decreasing the value of the
CONFIG_MQTT_KEEPALIVE
option or publishing data more frequently. AWS IoT specifies a maximum allowed keepalive of 1200 seconds (20 minutes), however in certain LTE networks, the Network Address Translation (NAT) timeout can be considerably lower. As a recommendation to prevent the likelihood of unexpected disconnects, set the optionCONFIG_MQTT_KEEPALIVE
to the highest value of the network NAT and maximum allowed MQTT keepalive.If publishing larger payloads fails, you might need to increase the value of the
CONFIG_MQTT_HELPER_RX_TX_BUFFER_SIZE
option.For nRF91 Series devices, the size of incoming messages cannot exceed approximately 2 kB. This is due to a limitation of the modem’s internal TLS buffers. Messages that exceed this limitation will be dropped.
AWS FOTA
The library supports FOTA using the AWS FOTA library.
This library can be enabled by setting the CONFIG_AWS_FOTA
Kconfig option.
To create a FOTA job, refer to the AWS FOTA documentation.
API documentation
include/net/aws_iot.h
subsys/net/lib/aws_iot/src/
- group aws_iot
Library used to connect an IP enabled device to the AWS IoT Core MQTT broker.
Typedefs
-
typedef void (*aws_iot_evt_handler_t)(const struct aws_iot_evt *evt)
AWS IoT library asynchronous event handler.
- Param evt:
[in] The event and any associated parameters.
Enums
-
enum aws_iot_shadow_topic_received_type
AWS IoT shadow received topic types. If a message is received on a subscribed shadow topic, the type will be set to the corresponding topic.
Values:
-
enumerator AWS_IOT_SHADOW_TOPIC_APPLICATION_SPECIFIC
This type is used if the message is published to an application specific topic.
-
enumerator AWS_IOT_SHADOW_TOPIC_GET_ACCEPTED
This topic type corresponds to $aws/things/<thing-name>/shadow/get/accepted. When requesting the shadow document and the request is accepted, the response is published to this topic.
-
enumerator AWS_IOT_SHADOW_TOPIC_GET_REJECTED
This topic type corresponds to $aws/things/<thing-name>/shadow/get/rejected. When requesting the shadow document and the request is rejected, the response is published to this topic. The response includes an error code that indicates the reason for rejection. The error code can be looked up in the AWS documentation under “Device Shadow error messages”.
-
enumerator AWS_IOT_SHADOW_TOPIC_UPDATE_DELTA
This topic type corresponds to $aws/things/<thing-name>/shadow/update/delta. When there is a mismatch between the state.reported and state.desired shadow properties The desired state is published to this topic. These desired properties should be updated on the device, and the device should report back its updated state to clear the delta.
-
enumerator AWS_IOT_SHADOW_TOPIC_UPDATE_ACCEPTED
This topic type corresponds to $aws/things/<thing-name>/shadow/update/accepted. When an update of the device shadow is accepted the device shadow document is published to this topic.
-
enumerator AWS_IOT_SHADOW_TOPIC_UPDATE_REJECTED
This topic type corresponds to $aws/things/<thing-name>/shadow/update/rejected. When an update of the device shadow is rejected a response is received on this topic with an error code stating the reason of rejection.
-
enumerator AWS_IOT_SHADOW_TOPIC_DELETE_ACCEPTED
This topic type corresponds to $aws/things/<thing-name>/shadow/delete/accepted. When the device shadow is deleted a message is sent to this topic.
-
enumerator AWS_IOT_SHADOW_TOPIC_DELETE_REJECTED
This topic type corresponds to $aws/things/<thing-name>/shadow/delete/rejected. When a deletion of the device shadow is rejected a response is published to this topic with an error code stating the reason for rejection.
-
enumerator AWS_IOT_SHADOW_TOPIC_APPLICATION_SPECIFIC
-
enum aws_iot_shadow_topic_type
AWS IoT shadow topic types. Used to address messages to the AWS IoT shadow service.
Values:
-
enumerator AWS_IOT_SHADOW_TOPIC_NONE
Unused default value.
-
enumerator AWS_IOT_SHADOW_TOPIC_GET
This topic type corresponds to $aws/things/<thing-name>/shadow/get, publishing an empty string to this topic requests the device shadow document.
-
enumerator AWS_IOT_SHADOW_TOPIC_UPDATE
This topic type corresponds to $aws/things/<thing-name>/shadow/update, publishing data to this topic updates the device shadow document.
-
enumerator AWS_IOT_SHADOW_TOPIC_DELETE
This topic type corresponds to $aws/things/<thing-name>/shadow/delete, publishing an empty string to this topic deletes the device shadow document.
-
enumerator AWS_IOT_SHADOW_TOPIC_NONE
-
enum aws_iot_evt_type
AWS IoT notification event types, used to signal the application.
Values:
-
enumerator AWS_IOT_EVT_CONNECTING
Connecting to the broker.
-
enumerator AWS_IOT_EVT_CONNECTED
Connected to the broker. Payload is of type bool (.data.persistent_session)
-
enumerator AWS_IOT_EVT_DISCONNECTED
Disconnected from the broker.
-
enumerator AWS_IOT_EVT_DATA_RECEIVED
Data received from the broker. Payload is of type aws_iot_data (.data.msg)
-
enumerator AWS_IOT_EVT_PUBACK
Acknowledgment for data sent to the broker. Payload is of type uint16_t (.data.message_id)
-
enumerator AWS_IOT_EVT_PINGRESP
Acknowledgment for pings sent to the broker.
-
enumerator AWS_IOT_EVT_FOTA_START
FOTA update start.
-
enumerator AWS_IOT_EVT_FOTA_DONE
FOTA done. Payload of type dfu_target_image_type (.data.image).
If the image parameter type is of type DFU_TARGET_IMAGE_TYPE_MCUBOOT the device needs to reboot to apply the new application image. If the image parameter type is of type DFU_TARGET_IMAGE_TYPE_MODEM_DELTA the modem needs to be reinitialized to apply the new modem image.
-
enumerator AWS_IOT_EVT_FOTA_ERASE_PENDING
FOTA erase pending.
-
enumerator AWS_IOT_EVT_FOTA_ERASE_DONE
FOTA erase done.
-
enumerator AWS_IOT_EVT_FOTA_DL_PROGRESS
FOTA progress notification. Payload is of type int (.data.fota_progress)
-
enumerator AWS_IOT_EVT_FOTA_ERROR
FOTA error. Something went wrong during the FOTA process, try again.
-
enumerator AWS_IOT_EVT_ERROR
Irrecoverable error, if this event is received the device should perform a reboot. Payload is of type int (.data.err)
-
enumerator AWS_IOT_EVT_CONNECTING
Functions
-
int aws_iot_init(aws_iot_evt_handler_t event_handler)
Initialize the library.
Note
This API must be called exactly once, and it must return successfully before any other library APIs can be called.
- Parameters:
event_handler – [in] Pointer to an event handler to receive library events.
- Return values:
0 – If successful.
-EINVAL – if an invalid parameter is passed in.
-
int aws_iot_connect(const struct aws_iot_config *const config)
Connect to the AWS IoT broker.
This function is synchronous and will only return success when the client has connected to the broker and all subscriptions (if any) have been acknowledged. If these conditions have not completed within CONFIG_AWS_IOT_CONNECT_TIMEOUT_SECONDS, the function times out and the application will need to call this function again.
- Parameters:
config – [out] Pointer to a structure that contains connection parameters. If this structure is passed in as NULL, static configurations set via Kconfig options are used. See CONFIG_AWS_IOT_BROKER_HOST_NAME and CONFIG_AWS_IOT_CLIENT_ID_STATIC.
- Return values:
0 – If successful.
-EAGAIN – If the client failed to connect within CONFIG_AWS_IOT_CONNECT_TIMEOUT_SECONDS.
-
int aws_iot_disconnect(void)
Disconnect from the AWS IoT broker.
- Return values:
0 – If successful.
-
int aws_iot_send(const struct aws_iot_data *const tx_data)
Send data to AWS IoT broker.
- Parameters:
tx_data – [in] Pointer to struct containing data to be transmitted to the AWS IoT broker.
- Return values:
0 – If successful.
-EINVAL – if an invalid parameter is passed in.
-ENODATA – if no valid topic nor shadow topic type is passed in.
-
int aws_iot_application_topics_set(const struct mqtt_topic *const list, size_t count)
Pass in a list of application specific topics that will be subscribed to upon connection to the AWS IoT broker. The number of application specific topics that the library can subscribe to is limited to 8.
Note
This function passes a reference to topics that are defined in the application. Therefore it is important that the memory of the passed in topic list is valid when aws_iot_connect() is called.
- Parameters:
list – [in] Pointer to list a of topics.
count – [in] Number of entries in the list.
- Return values:
0 – If successful.
-EINVAL – if an invalid parameter is passed in.
-
struct aws_iot_topic_data
- #include <aws_iot.h>
AWS IoT topic data.
Public Members
-
enum aws_iot_shadow_topic_type type
Optional: type of shadow topic that will be published to. When publishing to a shadow topic this can be set instead of the application specific topic below.
-
enum aws_iot_shadow_topic_received_type type_received
Type of shadow topic that the incoming message is received on. If a message is received on an application specific topic the type will be set to AWS_IOT_SHADOW_TOPIC_NONE.
-
const char *str
Pointer to string of application specific topic.
-
size_t len
Length of application specific topic.
-
enum aws_iot_shadow_topic_type type
-
struct aws_iot_data
- #include <aws_iot.h>
AWS IoT transmission data.
Public Members
-
struct aws_iot_topic_data topic
Topic data is sent/received on.
-
char *ptr
Pointer to data sent/received from the AWS IoT broker.
-
size_t len
Length of data.
-
uint16_t message_id
Message id, used to match acknowledgments.
-
uint8_t dup_flag
Duplicate flag. 1 indicates the message is a retransmission, Usually triggered by missing publication acknowledgment.
-
uint8_t retain_flag
Retain flag. 1 indicates to AWS IoT that the message should be stored persistently.
-
struct aws_iot_topic_data topic
-
struct aws_iot_evt
- #include <aws_iot.h>
Struct with data received from AWS IoT broker.
Public Members
-
enum aws_iot_evt_type type
Type of event.
-
struct aws_iot_data msg
Structure that contains data that was received from the broker.
-
int err
Error code that indicates reason of failure when receiving the AWS_IOT_EVT_ERROR event.
-
int fota_progress
FOTA progress in percentage.
-
bool persistent_session
Boolean that indicates if a previous MQTT session is being used.
-
uint16_t message_id
Message ID of the message that was acknowledged.
-
enum dfu_target_image_type image
DFU target type, used to determine if a reboot is required after FOTA based on the image that was updated.
See the documentation for the event AWS_IOT_EVT_FOTA_DONE for more information.
-
enum aws_iot_evt_type type
-
struct aws_iot_config
- #include <aws_iot.h>
Structure for AWS IoT broker connection parameters.
-
typedef void (*aws_iot_evt_handler_t)(const struct aws_iot_evt *evt)