Testing USMP on AWS EC2
This guide walks you through setting up a public test server on an AWS EC2 instance and connecting a local ESP32 microcontroller (using either the Arduino IDE or native ESP-IDF framework) to establish a secure, end-to-end encrypted USMP session over the Internet.
┌──────────────────────┐ Public Internet ┌──────────────────┐
│ ESP32 Client │ ──────────────────────────────────────> │ AWS EC2 Server │
│ (Arduino or ESP-IDF) │ TCP Port 9000 (AES-GCM-256 Secure) │ (Python Gateway) │
└──────────────────────┘ └──────────────────┘
1. AWS EC2 Server Code (server.py)
Save the following Python script as server.py on your Ubuntu EC2 instance:
import asyncio
import logging
from usmp import USMPServer, USMPSession, USMPProtocol
logging.basicConfig(level=logging.INFO, format="[%(asctime)s] [%(levelname)s] %(message)s")
DEV_PSK = b"usmp-dev-psk-change-me-before-prod"
server = USMPServer(
host="0.0.0.0",
port=9000,
psk=DEV_PSK,
protocol=USMPProtocol.TCP
)
@server.on_session
async def handle_ec2_client(session: USMPSession):
print("=" * 60)
print(" USMP SECURE SERVER (EC2)")
print("=" * 60)
print(f"[SESSION ESTABLISHED]")
print(f" Device ID: {session.device_id}")
print(f" Session ID: {session.session_id}")
print("=" * 60)
try:
async for data in session:
text = data.decode("utf-8", errors="replace")
print(f"[RX from {session.device_id}]: {text}")
reply = f"Echo from EC2: {text}"
await session.send(reply.encode("utf-8"))
print(f"[TX to {session.device_id}]: {reply}")
except Exception as err:
print(f"[SESSION EXCEPTION] {session.device_id}: {err}")
async function main():
print("============================================================")
print(" USMP SECURE SERVER (EC2)")
print("============================================================")
print("Listening on: 0.0.0.0:9000")
print("Protocol: TCP")
print("============================================================")
print("Starting server... Press Ctrl+C to stop.\n")
await server.serve()
if __name__ == "__main__":
asyncio.run(main())
2. Arduino IDE Client Code (arduino.ino)
Below is the Arduino IDE sketch configured for connecting across the public Internet to your EC2 instance:
#include <WiFi.h>
#include <USMP.h>
// Enter your AWS EC2 Public IP and Wi-Fi Details
#define EC2_PUBLIC_IP "203.0.113.10" // Replace with your EC2 Public IPv4
#define EC2_PORT 9000
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASS "YOUR_WIFI_PASSWORD"
const char *DEV_PSK = "usmp-dev-psk-change-me-before-prod";
USMPClient usmp(DEV_PSK);
unsigned long lastPing = 0;
int pingCount = 0;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n==========================================");
Serial.println(" ESP32 USMP EC2 Public Cloud Client");
Serial.println("==========================================");
Serial.printf("Connecting to Wi-Fi: %s\n", WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.printf("\nWi-Fi Connected! IP: %s\n", WiFi.localIP().toString().c_str());
Serial.printf("Connecting to USMP EC2 Server: %s:%d\n", EC2_PUBLIC_IP, EC2_PORT);
USMPTCPTransport transport = USMP::TCP(EC2_PUBLIC_IP, EC2_PORT);
usmp.onConnect([]() {
Serial.println("\n[SUCCESS] Secure USMP session established with AWS EC2!");
});
usmp.onMessage([](const uint8_t *data, size_t len) {
String msg = String((char*)data).substring(0, len);
Serial.printf("Received from EC2: %s\n", msg.c_str());
});
if (!usmp.begin(transport)) {
Serial.println("[ERROR] Failed to connect to AWS EC2.");
}
}
void loop() {
usmp.loop();
if (millis() - lastPing > 5000) {
lastPing = millis();
pingCount++;
if (usmp.isConnected()) {
String msg = "ESP32 Ping #" + String(pingCount) + " (Uptime: " + String(millis()/1000) + "s)";
Serial.printf("Sending: %s\n", msg.c_str());
usmp.send((const uint8_t*)msg.c_str(), msg.length());
}
}
}
3. ESP-IDF Native Client Code (main/app.c)
Below is the ESP-IDF client source file main/app.c:
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "usmp.h"
#include "usmp_transport_tcp.h"
static const char *TAG = "EC2_CLIENT";
#define EC2_PUBLIC_IP "203.0.113.10" // Replace with your EC2 Public IPv4
#define EC2_PORT 9000
#define DEV_PSK "usmp-dev-psk-change-me-before-prod"
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_LOGI(TAG, "Starting EC2 Client application...");
usmp_context_t ctx;
usmp_transport_t transport;
usmp_init(&ctx, DEV_PSK);
usmp_transport_tcp_init(&transport, EC2_PUBLIC_IP, EC2_PORT);
ESP_LOGI(TAG, "Connecting to EC2 server %s:%d...", EC2_PUBLIC_IP, EC2_PORT);
if (usmp_connect(&ctx, &transport) != USMP_OK) {
ESP_LOGE(TAG, "Failed to connect to EC2!");
return;
}
ESP_LOGI(TAG, "[SUCCESS] Secure USMP session established with EC2!");
char ping_msg[64] = "Hello EC2, this is ESP32 via USMP!";
if (usmp_send(&ctx, &transport, (const uint8_t*)ping_msg, strlen(ping_msg)) == USMP_OK) {
uint8_t rx_buf[256];
size_t rx_len = 0;
if (usmp_recv(&ctx, &transport, rx_buf, sizeof(rx_buf), &rx_len, 5000) == USMP_OK) {
rx_buf[rx_len] = '\0';
ESP_LOGI(TAG, "Received from EC2: %s", (char*)rx_buf);
}
}
usmp_close(&ctx, &transport);
}
Deployment & Execution Steps
1. Configure Inbound Rules on AWS EC2
In the AWS EC2 Console, open your Security Group inbound rules and add a rule allowing Custom TCP, Port 9000, Source 0.0.0.0/0.
2. Run the EC2 Server
pip install usmp
python3 server.py
3. Flash and Monitor Microcontroller
Upload arduino.ino in Arduino IDE or flash app.c in ESP-IDF:
idf.py -p COMx flash monitor
4. Verify Output Logs
Upon boot, your ESP32 serial monitor will display:
Connecting to USMP EC2 Server: 203.0.113.10:9000
[SUCCESS] Secure USMP session established!
Sending: ESP32 Ping #1 (Uptime: 5s)
Received from EC2: Echo from EC2: ESP32 Ping #1 (Uptime: 5s)