We're attempting to provision one of our nRF9160-based IoT devices to our AWS VPC.
We're following this procedure:
Provisioning our eDude on AWS
Step 1: Provision the IoT Device (nRF9160)
- Install Required Software
Ensure your development environment is set up with:
- nRF Connect for Desktop (for flashing firmware)
- nRF SDK (nRF Connect SDK) – includes Zephyr RTOS
- AWS IoT SDK for C (optional)
- Segger Embedded Studio or VS Code with Zephyr extension (for development)
- Prepare Device Credentials
You'll need to securely load AWS IoT credentials onto your nRF9160:
- Obtain the AWS IoT Core Certificates
- certificate.pem.crt
- private.pem.key
- AmazonRootCA1.pem
- Download the following from AWS IoT Core:
- Convert to a format suitable for your embedded system (if needed).
- Flash Certificates to the Device
- Store the certificates in non-volatile storage (e.g., CONFIG_NVS in Zephyr).
- Example approach using Zephyr's LittleFS or Flash FS:
- #define CERTIFICATE_PATH "/certs/device_cert.pem"
- #define PRIVATE_KEY_PATH "/certs/private_key.pem"
- #define ROOT_CA_PATH "/certs/AmazonRootCA1.pem"
- If using modem security credentials, provision certificates via AT commands:
- AT%CMNG=0,16842753,0,"-----BEGIN CERTIFICATE-----..."
- AT%CMNG=0,16842754,0,"-----BEGIN RSA PRIVATE KEY-----..."
- AT%CMNG=0,16842755,0,"-----BEGIN CERTIFICATE-----..."
- Verify storage using: AT%CMNG=1
- Configure nRF9160 for Secure MQTT Connection
Modify your Zephyr application’s prj.conf:
CONFIG_MQTT_LIB=y
CONFIG_MQTT_LIB_TLS=y
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NRF_MODEM_LIB=y
CONFIG_NRF_CLOUD_MQTT=y
Set up AWS endpoint and credentials in Kconfig:
CONFIG_AWS_IOT_BROKER_HOST_NAME= “a3iodo1wh9ldbz-ats.iot.us-west-2.amazonaws.com"
CONFIG_AWS_IOT_SEC_TAG=12345
- Replace "your-endpoint.amazonaws.com" with your AWS IoT Endpoint (found under IoT Core → Settings).
- Set up AWS IoT security tag for modem storage (12345 is just an example).
Step 2: Connect nRF9160 to AWS IoT Core
Now, let's establish an MQTT connection and test message exchange.
- Initialize LTE & Connect to AWS IoT
Modify your Zephyr application’s main file (main.c):
#include <zephyr.h>
#include <net/mqtt.h>
#include <modem/lte_lc.h>
#include <modem/modem_key_mgmt.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(my_mqtt_app, LOG_LEVEL_INF);
#define AWS_BROKER #define AWS_BROKER "a3iodo1wh9ldbz-ats.iot.us-west-2.amazonaws.com"
#define AWS_PORT 8883
#define MQTT_CLIENT_ID "nRF9160_device"
// MQTT buffers
static uint8_t rx_buffer[512];
static uint8_t tx_buffer[512];
static struct mqtt_client client;
static struct sockaddr_storage broker;
// Callback for MQTT events
void mqtt_event_handler(struct mqtt_client *client, const struct mqtt_evt *evt) {
switch (evt->type) {
case MQTT_EVT_CONNACK:
LOG_INF("MQTT connected");
break;
case MQTT_EVT_DISCONNECT:
LOG_INF("MQTT disconnected");
break;
case MQTT_EVT_PUBLISH:
LOG_INF("Message received: %s", evt->param.publish.message.payload.data);
break;
default:
break;
}
}
// Function to configure MQTT client
void mqtt_init(void) {
struct sockaddr_in *broker4 = (struct sockaddr_in *)&broker;
broker4->sin_family = AF_INET;
broker4->sin_port = htons(AWS_PORT);
net_addr_pton(AF_INET, AWS_BROKER, &broker4->sin_addr);
mqtt_client_init(&client);
client.broker = &broker;
client.evt_cb = mqtt_event_handler;
client.client_id.utf8 = MQTT_CLIENT_ID;
client.client_id.size = strlen(MQTT_CLIENT_ID);
client.transport.type = MQTT_TRANSPORT_SECURE;
client.rx_buf = rx_buffer;
client.rx_buf_size = sizeof(rx_buffer);
client.tx_buf = tx_buffer;
client.tx_buf_size = sizeof(tx_buffer);
}
// Function to connect to MQTT broker
void mqtt_connect(void) {
int err = mqtt_connect(&client);
if (err) {
LOG_ERR("MQTT connection failed: %d", err);
return;
}
LOG_INF("MQTT connection successful");
}
// Entry point
void main(void) {
LOG_INF("Initializing LTE...");
lte_lc_init_and_connect(); // Establish LTE connection
LOG_INF("Setting up MQTT...");
mqtt_init();
mqtt_connect();
}
- Publish Messages to AWS IoT
After establishing a connection, send an MQTT message:
void send_mqtt_message(void) {
struct mqtt_publish_param param;
char payload[] = "{ \"status\": \"active\", \"temperature\": 25 }";
param.message.topic.qos = MQTT_QOS_0_AT_MOST_ONCE;
param.message.topic.topic.utf8 = "iot/device/data";
param.message.topic.topic.size = strlen(param.message.topic.topic.utf8);
param.message.payload.data = payload;
param.message.payload.len = strlen(payload);
param.message_id = sys_rand32_get();
int err = mqtt_publish(&client, ¶m);
if (err) {
LOG_ERR("Failed to publish message: %d", err);
} else {
LOG_INF("Message published successfully");
}
}
- Subscribe to Incoming Commands
Modify the MQTT event handler to process received messages:
case MQTT_EVT_PUBLISH: {
struct mqtt_publish_param *p = &evt->param.publish;
LOG_INF("Received topic: %.*s", p->message.topic.topic.size, p->message.topic.topic.utf8);
LOG_INF("Payload: %.*s", p->message.payload.len, (char *)p->message.payload.data);
break;
}
We have successfully flashed the certificates into the modem, however, the MQTT connection attempt times out. Not sure how to troubleshoot this.
Can offer any advice?