A comprehensive, production-ready template for connecting ESP32 devices to AWS IoT Core using Rust. This project demonstrates modern IoT architecture with secure MQTT communications, automated cloud infrastructure provisioning, and clean, maintainable firmware code.
- π Secure MQTT over TLS - End-to-end encrypted communication with AWS IoT Core
- ποΈ Infrastructure as Code - Complete Terraform automation for AWS resources
- π¦ Modern Rust Firmware - Clean, safe, and efficient ESP32 code using esp-idf-svc
- β‘ Non-blocking Architecture - Efficient message processing without blocking main thread
- π§ Configuration-driven - No hardcoded secrets, all settings via TOML files
- π Automatic Certificate Management - Seamless certificate provisioning and loading
-
Development Environment
- Follow the comprehensive installation guide from the official ESP Rust Book
- Install
espflash
using this book guide - Install
espmonitor
using the official repository - Install
aws-cli
using the official docs - Install
terraform
using the official docs
-
AWS Environment
# Install and configure AWS CLI aws configure # Install Terraform # Visit: https://www.terraform.io/downloads.html
git clone <repository-url>
cd aws-iot-esp32-example
cd terraform
# Copy and configure variables
cp terraform.tfvars.example terraform.tfvars
Edit terraform.tfvars
to create multiple ESP32 devices:
# Create multiple ESP32 things (esp32s3 and esp32c3)
things = [
{
name = "esp32s3"
topic_prefix = "esp32"
},
{
name = "esp32c3"
topic_prefix = "esp32"
}
]
region = "us-east-1" # Your AWS region
tags = {
Project = "ESP32-IoT-Multi-Device"
Environment = "development"
Owner = "your-name"
}
Deploy infrastructure:
terraform init
terraform plan
terraform apply # Type 'yes' to confirm
This will create:
- Two IoT Things:
esp32s3
andesp32c3
- Separate certificate directories:
certs/esp32s3/
andcerts/esp32c3/
- Shared MQTT topics: Both devices use
esp32/*
topic prefix - Individual policies: Each device gets its own policy and certificates
cd ../firmware/example
# Copy ESP32-S3 certificates
cp -r ../../terraform/certs/esp32s3/ ./certs/
# Create ESP32-S3 configuration
cp cfg.toml.example cfg.toml
Edit cfg.toml
for ESP32-S3:
[example]
# Wi-Fi Configuration
wifi_ssid = "YOUR_WIFI_NETWORK"
wifi_pass = "YOUR_WIFI_PASSWORD"
# AWS IoT Configuration (from Terraform output)
mqtt_url = "mqtts://your-endpoint.iot.region.amazonaws.com"
mqtt_client_id = "esp32s3"
mqtt_topic_pub = "esp32/pub"
mqtt_topic_sub = "esp32/sub"
# Certificate paths (ESP32-S3 specific)
cert_ca = "certs/AmazonRootCA1.pem"
cert_crt = "certs/[certificate-id]-certificate.pem.crt"
cert_key = "certs/[certificate-id]-private.pem.key"
cd firmware/example
# Configure for ESP32-S3 (Xtensa architecture)
# Make sure your .cargo/config.toml has:
# target = "xtensa-esp32s3-espidf"
# Build firmware
cargo build --release
# Flash to ESP32-S3 device (ensure device is connected via USB)
cargo run --release
# Or flash manually
espflash flash --monitor target/xtensa-esp32s3-espidf/release/example
cd ../exampleC3
# Configure for ESP32-C3 (RISC-V architecture)
# Update .cargo/config.toml with:
# target = "riscv32imc-esp-espidf"
# Clean previous builds when switching architectures
cargo clean
# Build firmware
cargo build --release
# Flash to ESP32-C3 device (ensure device is connected via USB)
cargo run --release
# Or flash manually
espflash flash --monitor target/riscv32imc-esp-espidf/release/example
The project supports multiple ESP32 variants with different architectures. Choose the configuration that matches your hardware.
π Reference: See all supported targets at esp-idf-svc examples
Step 1: Install Required Toolchain
ESP32 variants use different architectures requiring specific toolchains:
# For Xtensa-based chips (ESP32, ESP32-S2, ESP32-S3)
espup install --targets esp32,esp32s2,esp32s3
# For RISC-V-based chips (ESP32-C3, ESP32-C6, ESP32-H2)
espup install --targets esp32c3,esp32c6,esp32h2
# Or install all targets at once
espup install --targets all
# Source environment (required every terminal session)
source ~/export-esp.sh
Step 2: Update .cargo/config.toml
Choose the appropriate configuration for your target:
ESP32-S3 (Xtensa Architecture):
[build]
target = "xtensa-esp32s3-espidf"
[target.xtensa-esp32s3-espidf]
linker = "ldproxy"
runner = "espflash flash --monitor"
rustflags = ["--cfg", "espidf_time64"]
[unstable]
build-std = ["std", "panic_abort"]
[env]
MCU = "esp32s3"
ESP_IDF_VERSION = "v5.3.2"
ESP32-C3 (RISC-V Architecture):
[build]
target = "riscv32imc-esp-espidf"
[target.riscv32imc-esp-espidf]
linker = "ldproxy"
runner = "espflash flash --monitor"
[unstable]
build-std = ["std", "panic_abort"]
[env]
MCU = "esp32c3"
ESP_IDF_VERSION = "v5.3.2"
ESP32 (Original - Xtensa Architecture):
[build]
target = "xtensa-esp32-espidf"
[target.xtensa-esp32-espidf]
linker = "ldproxy"
runner = "espflash flash --monitor"
rustflags = ["--cfg", "espidf_time64"]
[unstable]
build-std = ["std", "panic_abort"]
[env]
MCU = "esp32"
ESP_IDF_VERSION = "v5.3.2"
Step 3: Clean and Rebuild
When switching targets, always clean previous builds:
cargo clean
cargo build --release
The Terraform module creates:
- IoT Thing - Device representation in AWS IoT Core
- Device Certificate - X.509 certificate for secure authentication
- IoT Policy - Permissions for MQTT operations
- Certificate Downloads - Automatic retrieval of all required certificates
Output includes:
# Example Terraform output
mqtt_endpoint = "a1b2c3d4e5f6g7.iot.us-east-1.amazonaws.com"
thing_name = "my-esp32-device-001"
certificate_arn = "arn:aws:iot:us-east-1:123456789012:cert/a1b2c3..."
# Ready-to-use cfg.toml template displayed
Certificates are automatically organized:
certs/
βββ AmazonRootCA1.pem # AWS Root CA
βββ device-certificate.pem.crt # Your device certificate
βββ private-key.pem.key # Device private key
The ESP32 device now communicates using structured JSON messages:
{
"message": "command_name"
}
{
"message": "response_content"
}
Command | Description | Example Request | Example Response |
---|---|---|---|
ping |
Connectivity test | {"message": "ping"} |
{"message": "pong"} |
Any other | Unknown command | {"message": "test"} |
{"message": "Unknown action: test"} |
Plain text | Fallback for non-JSON | Hello World |
{"message": "Plain text: Hello World"} |
1. Send ping command:
# Publish to: sensors/commands
{"message": "ping"}
2. Receive response:
# Received on: sensors/data
{"message": "pong"}
3. Send unknown command:
# Publish to: sensors/commands
{"message": "status"}
4. Receive error response:
# Received on: sensors/data
{"message": "Unknown action: status"}
Add new commands by modifying the match statement in main.rs
:
let response = match msg.message.as_str() {
"ping" => JsonMessage { message: "pong".to_string() },
"get_status" => JsonMessage {
message: "Device online".to_string()
},
"restart" => {
// Handle restart command
JsonMessage { message: "Restarting...".to_string() }
},
_ => JsonMessage {
message: format!("Unknown action: {}", msg.message)
},
};
Setting | Description | Example |
---|---|---|
wifi_ssid |
WiFi network name | "MyNetwork" |
wifi_pass |
WiFi password | "SecurePassword123" |
mqtt_url |
AWS IoT endpoint | "mqtts://abc123.iot.us-east-1.amazonaws.com" |
mqtt_client_id |
Unique device ID | "sensor-001" |
mqtt_topic_pub |
Publish topic | "sensors/temperature" |
mqtt_topic_sub |
Subscribe topic | "commands/led" |
Setting | Description | Default |
---|---|---|
cert_ca |
Root CA certificate | "certs/AmazonRootCA1.pem" |
cert_crt |
Device certificate | "certs/device-certificate.pem.crt" |
cert_key |
Private key | "certs/private-key.pem.key" |
espflash monitor
Look for these success indicators:
I (1234) example: WiFi connected successfully
I (1235) example: MQTT client created successfully
I (1236) example: Subscribed to topic "sensors/commands"
I (1237) example: Starting main application loop
Using AWS IoT Core Test Console:
- Go to AWS IoT Core β Test β MQTT test client
- Subscribe to your device's publish topic:
sensors/data
- Publish to your device's subscribe topic:
sensors/commands
Send JSON commands:
{
"message": "ping"
}
Expected JSON response:
{
"message": "pong from {your mqtt thing id}"
}
Check AWS IoT Core logs in CloudWatch for successful connections.
- Binary Size: ~2.5MB (reduced from 3MB after removing anyhow)
- Memory Usage: ~200KB RAM for MQTT operations
- CPU Usage: Non-blocking architecture minimizes CPU overhead
- Network: Efficient MQTT keep-alive and message batching
- Fork the repository
- Create feature branch:
git checkout -b feature/amazing-feature
- Test on real hardware
- Update documentation
- Submit pull request
GPL-3.0 License - see LICENSE file for details.
- π ESP-IDF Documentation
- π¦ Rust on ESP Book
- π Report Issues
- π¬ Discussions
Built with β€οΈ for the IoT community