A complete, foundational solution for connecting an ESP32 to AWS IoT Core over secure MQTT — publishing live sensor data with NTP timestamps to the cloud and receiving LED control commands from AWS.
- Overview
- Prerequisites
- AWS IoT Configuration
- Arduino IDE Setup
- Firmware
- Testing MQTT Connectivity
- Summary & Next Steps
- References
This project demonstrates two-way MQTT communication between an ESP32 microcontroller and AWS IoT Core:
| Direction | Topic | Payload |
|---|---|---|
| ESP32 → AWS | MQTT_PUB_TOPIC |
JSON with epoch timestamp + hall-effect sensor reading |
| AWS → ESP32 | MQTT_SUB_TOPIC |
ON or OFF to control the built-in LED |
The ESP32 connects to an NTP server to timestamp sensor readings, and controls a programmable LED (GPIO 13) based on commands received from the cloud.
This solution uses the Adafruit HUZZAH32 (WROOM32-based), but any generic ESP32 development board supported by the Arduino IDE will work.
Watch the final integration demo: youtu.be/6Ir94C9GlVk
| Requirement | Details |
|---|---|
| AWS Account | Needed to create an AWS IoT Thing, certificates, and policy |
| ESP32 board | Adafruit HUZZAH32 or any Arduino-compatible ESP32 module |
| Arduino IDE | With USB-serial driver for your specific ESP32 model |
| Sensors / Actuators | This solution uses the ESP32's built-in hall-effect sensor and programmable LED |
- Sign in to the AWS IoT Console
- In the left nav, select Settings
- Copy the Device data endpoint — it will look like:
xxxxxxxxxxxxxx.iot.us-east-1.amazonaws.com
- In the left nav, go to Security > Policies, then Create a policy
- Enter a name (e.g.
esp32_iot_policy) - Select Advanced mode and paste the policy below
- Click Create
Note: This policy grants broad permissions for prototyping. Restrict it to specific topics and actions before any production use.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:*",
"Resource": "*"
}
]
}-
Go to Manage > All devices > Things > Create > Create a single thing
-
Enter a Thing name — you'll use this in
secrets.hasAWS_THINGNAME -
Click Next, then select Auto-generate a new certificate
-
Download all four files:
File Used for Device certificate ( .crt)AWS_CRTinsecrets.hPrivate key ( .key)AWS_PRIVATEinsecrets.hPublic key (not needed in firmware) Amazon Root CA 1 Pre-filled in secrets.h -
Click Activate, then Attach Policy and select the policy you created
-
Click Register Thing
-
Download and install the Arduino IDE
-
Install the USB-serial driver for your ESP32 model
-
Open Preferences and add the following URL to Additional Board Manager URLs:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
-
Go to Tools > Board > Boards Manager, search
esp32(by Espressif Systems), and install -
Select Tools > Board > ESP32 Arduino > ESP32 Dev Module
Go to Sketch > Include Library > Manage Libraries and install the following:
| Library | Author | Purpose |
|---|---|---|
| ArduinoJson | Benoit Blanchon | Serialize sensor data to JSON |
| NTPClient | Fabrice Weinberg | Get real-time timestamps from NTP servers |
| arduino-mqtt | Joel Gaehwiler | Lightweight MQTT client |
If a library isn't found in the manager, download the ZIP from its GitHub repo and use Sketch > Include Library > Add .ZIP File.
Create a new sketch (File > New) and paste:
// updated: 9/26/2020 by MBX
#include "secrets.h"
#include <WiFiClientSecure.h>
#include <MQTTClient.h>
#include <ArduinoJson.h>
#include "WiFi.h"
#include <NTPClient.h>
#include <WiFiUdp.h>
#define LED_PIN 13
WiFiClientSecure iot = WiFiClientSecure();
MQTTClient client = MQTTClient(256);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "north-america.pool.ntp.org");
void connectToWiFi()
{
Serial.println("\nConnecting to Wi-Fi");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(200);
Serial.print("..");
}
Serial.println("\nSUCCESS: Connected to Wi-Fi");
Serial.print("Wi-Fi SSID: ");
Serial.println(WIFI_SSID);
}
void connectToAWSIoT()
{
Serial.print("\n\nConnecting to AWS IoT");
iot.setCertificate(AWS_CRT);
iot.setPrivateKey(AWS_PRIVATE);
iot.setCACert(AWS_CA);
client.begin(AWS_ENDPOINT, 8883, iot);
client.onMessage(messageHandler);
while (!client.connect(AWS_THINGNAME)) {
Serial.print(".");
delay(200);
}
if (!client.connected()) {
Serial.println("\nERROR: AWS IoT Connection Timeout");
return;
}
client.subscribe(MQTT_SUB_TOPIC);
Serial.println("\nSUCCESS: AWS IoT Endpoint Connected\n");
Serial.print("\nAWS IoT Publish Topic: "); Serial.println(MQTT_PUB_TOPIC);
Serial.print("\nAWS IoT Subscribe Topic: "); Serial.println(MQTT_SUB_TOPIC);
Serial.print("\nAWS IoT Thing Name: "); Serial.println(AWS_THINGNAME);
Serial.print("\nAWS IoT Endpoint: "); Serial.println(AWS_ENDPOINT);
Serial.println("\n");
}
void publishPayload()
{
StaticJsonDocument<200> doc;
doc["time"] = timeClient.getEpochTime();
doc["sensor01"] = hallRead();
char jsonBuffer[512];
serializeJson(doc, jsonBuffer);
Serial.println(jsonBuffer);
client.publish(MQTT_PUB_TOPIC, jsonBuffer);
}
void messageHandler(String &topic, String &payload) {
Serial.println("\nAWS incoming MQTT topic: " + topic);
Serial.println("\nAWS incoming MQTT payload: " + payload);
if (payload == "ON") digitalWrite(LED_PIN, HIGH);
if (payload == "OFF") digitalWrite(LED_PIN, LOW);
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
delay(2000);
connectToWiFi();
connectToAWSIoT();
timeClient.begin();
}
void loop() {
timeClient.update();
publishPayload();
client.loop();
delay(1000);
}Create a new tab in the sketch named secrets.h and paste:
#include <pgmspace.h>
// Generated by the AWS IoT service
#define AWS_THINGNAME "yourThingName"
// https://docs.aws.amazon.com/iot/latest/developerguide/topics.html
#define MQTT_PUB_TOPIC "yourPublishTopic"
#define MQTT_SUB_TOPIC "yourSubscribeTopic"
const char WIFI_SSID[] = "YourSSID";
const char WIFI_PASSWORD[] = "YourSSIDpassword";
const char AWS_ENDPOINT[] = "YourAWSIoTEndpoint-ats.iot.us-east-1.amazonaws.com";
// Insert IoT Device Certificate generated by the AWS IoT service
static const char AWS_CRT[] PROGMEM = R"KEY(
-----BEGIN CERTIFICATE-----
insert your device cert here
-----END CERTIFICATE-----
)KEY";
// Insert IoT Device Private Key generated by the AWS IoT service
static const char AWS_PRIVATE[] PROGMEM = R"KEY(
-----BEGIN RSA PRIVATE KEY-----
insert your device private key here
-----END RSA PRIVATE KEY-----
)KEY";
// Amazon Root CA 1
// https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html
static const char AWS_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
rqXRfboQnoZsG4q5WTP468SQvvG5
-----END CERTIFICATE-----
)EOF";Update secrets.h with values gathered during AWS setup:
-
WIFI_SSIDandWIFI_PASSWORD -
AWS_ENDPOINT(your device data endpoint) -
AWS_THINGNAME(your IoT Thing name) -
AWS_CRT(device certificate contents) -
AWS_PRIVATE(private key contents) -
MQTT_PUB_TOPICandMQTT_SUB_TOPIC
Then:
- Connect your ESP32 to your workstation via USB
- Select the correct COM/serial port in the Arduino IDE
- Upload the sketch to your ESP32
- Open the Serial Monitor at
115200baud and confirm WiFi + AWS connectivity
-
Open the AWS IoT Console and navigate to Test > MQTT test client
-
Subscribe to your publish topic (
MQTT_PUB_TOPIC) — you should see JSON payloads arriving every second:{ "time": 1601234567, "sensor01": 42 } -
Publish to your subscribe topic (
MQTT_SUB_TOPIC) with payloadONorOFF(uppercase)- The LED on your ESP32 should respond immediately
- The command will also appear in the Arduino Serial Monitor
This solution gives you a secure, bidirectional MQTT link between an ESP32 and AWS IoT Core. With this foundation in place, you can extend it using the full AWS ecosystem:
| AWS Service | Use Case |
|---|---|
| DynamoDB / Timestream | Archive sensor readings in a database |
| Lambda | Trigger serverless actions on sensor thresholds |
| SNS / SES | Send alerts when values exceed limits |
| QuickSight | Visualize device data in real time |
| SageMaker | Feed data into ML models for predictive maintenance |
| Greengrass | Run edge compute logic on the device itself |
| Resource | Link |
|---|---|
| Espressif ESP32 | espressif.com |
| Arduino IDE | arduino.cc |
| ArduinoJson | github.com/bblanchon/ArduinoJson |
| arduino-mqtt | github.com/256dpi/arduino-mqtt |
| NTPClient | github.com/arduino-libraries/NTPClient |
| AWS IoT Core | aws.amazon.com/iot |
| Adafruit HUZZAH32 | adafruit.com/product/3405 |
| SparkFun ESP32 Thing | sparkfun.com/products/13907 |
| Moheeb Zara's AWS IoT guide | aws.amazon.com/blogs/compute/… |
| Gourav Das's guide | hackernoon.com |
| Mudassar Tamboli's guide | medium.com/@mudassar.tamboli/… |
MIT License © 2020 Mike Bitar




