我有一个 esp32 设备,该设备具有我在 AWS 中生成的证书,可用作声明证书。 esp32 可以很好地连接到 AWS,并允许我订阅接受和拒绝的主题。当我发布到 $aws/certificates/create/json 主题时,aws 中会生成一个新证书,并等待激活,但 esp32 没有收到来自 AWS 的有关接受或拒绝主题的消息。
#include <ArduinoJson.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <SPIFFS.h> // For saving credentials
#include <Secrets.h>
// WiFi credentials
const char* ssid = "";
const char* password = "";
const char* awsCertTopic = "$aws/certificates/create/json"; // MQTT topic for creating new Certificate
const char* awsCertAccepted = "$aws/certificates/create/json/accepted"; // MQTT topic for new Certificate Accepted
const char* awsCertRejected = "$aws/certificates/create/json/rejected"; // MQTT topic for new Certificate Rejected
const char* awsFleetTopic = "$aws/provisioning-templates/DrainAlert_FleetTemplate/provision/json"; // MQTT topic for fleet provisioning
const char* awsFleetAccepted = "$aws/provisioning-templates/DrainAlert_FleetTemplate/provision/json/accepted"; // MQTT topic for fleet provisioning Accepted
const char* awsFleetRejected = "$aws/provisioning-templates/DrainAlert_FleetTemplate/provision/json/rejected"; // MQTT topic for fleet provisioning Rejected
const char* awsTestTopic = "ji/tp";
// Time Sync details
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0;
const int daylightOffset_sec = 3600;
// WiFiClientSecure for secure MQTT connection
WiFiClientSecure wifiClient;
PubSubClient mqttClient(wifiClient);
void setupTime() {
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Serial.println("Waiting for NTP time sync...");
while (!time(nullptr)) {
delay(1000);
Serial.print(".");
}
Serial.println("\nTime synchronized");
}
// Function to save the new certificate and private key to SPIFFS
void saveCredentials(const char* cert, const char* privateKey) {
if (!SPIFFS.begin(true)) {
Serial.println("Failed to mount file system");
return;
}
// Save certificate
File certFile = SPIFFS.open("/deviceCert.pem", FILE_WRITE);
if (certFile) {
certFile.print(cert);
certFile.close();
Serial.println("Saved new certificate");
} else {
Serial.println("Failed to open cert file for writing");
}
// Save private key
File keyFile = SPIFFS.open("/privateKey.pem", FILE_WRITE);
if (keyFile) {
keyFile.print(privateKey);
keyFile.close();
Serial.println("Saved new private key");
} else {
Serial.println("Failed to open key file for writing");
}
SPIFFS.end();
}
// Callback function to handle MQTT messages
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.println(topic);
// Convert payload to a string
String payloadStr = String((char*)payload).substring(0, length);
Serial.print("Payload: " + payloadStr);
// Handle the provisioning response
if (strcmp(topic, "$aws/certificates/create/json/accepted") == 0) {
Serial.println("Provisioning successful. Saving new credentials...");
// Parse JSON to extract certificate and private key
String newCert = extractCertFromPayload(payloadStr);
String newPrivateKey = extractPrivateKeyFromPayload(payloadStr);
// Save the new credentials
saveCredentials(newCert.c_str(), newPrivateKey.c_str());
}
}
String extractCertFromPayload(String payload) {
StaticJsonDocument<1024> doc;
deserializeJson(doc, payload);
return doc["certificatePem"].as<String>();
}
String extractPrivateKeyFromPayload(String payload) {
StaticJsonDocument<1024> doc;
deserializeJson(doc, payload);
return doc["privateKey"].as<String>();
}
void connectToWiFi() {
Serial.print("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("Connected!");
}
void connectToMQTT() {
wifiClient.setCACert(awsRootCA);
wifiClient.setCertificate(claimCert);
wifiClient.setPrivateKey(claimPrivateKey);
mqttClient.setServer(awsEndpoint, awsPort);
mqttClient.setCallback(mqttCallback);
while (!mqttClient.connected()) {
Serial.print("Connecting to AWS IoT...");
if (mqttClient.connect("DnAtClient")) {
Serial.println("Connected!");
// Subscribe to provisioning response topics
mqttClient.subscribe(awsCertAccepted);
if (mqttClient.subscribe(awsCertAccepted)) {
Serial.println("Successfully subscribed to awsCertificateAccepted topic");
} else {
Serial.println("Failed to subscribe to awsCertificateAccepted topic");
}
mqttClient.subscribe(awsCertRejected);
if (mqttClient.subscribe(awsCertRejected)) {
Serial.println("Successfully subscribed to awsCertificateRejected topic");
} else {
Serial.println("Failed to subscribe to awsCertificateRejected topic");
}
mqttClient.subscribe(awsFleetAccepted);
if (mqttClient.subscribe(awsFleetAccepted)) {
Serial.println("Successfully subscribed to awsFleetAccepted topic");
} else {
Serial.println("Failed to subscribe to awsFleetAccepted topic");
}
mqttClient.subscribe(awsFleetRejected);
if (mqttClient.subscribe(awsFleetRejected)) {
Serial.println("Successfully subscribed to awsFleetRejected topic");
} else {
Serial.println("Failed to subscribe to awsFleetRejected topic");
}
mqttClient.subscribe(awsTestTopic);
if (mqttClient.subscribe(awsTestTopic)) {
Serial.println("Successfully subscribed to awsTestTopic topic");
} else {
Serial.println("Failed to subscribe to awsTestTopic topic");
}
} else {
Serial.print("Failed to connect, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void triggerCertCreation() {
String payload = "{}";
mqttClient.publish(awsCertTopic, payload.c_str());
Serial.println("New Certificate Request Sent...");
}
void reconnect() {
while (!mqttClient.connected()) {
Serial.print("Attempting MQTT connection...");
if (mqttClient.connect("ESP32Client")) {
Serial.println("connected");
mqttClient.subscribe(awsFleetAccepted);
mqttClient.subscribe(awsFleetRejected);
} else {
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(6, OUTPUT);
pinMode(9, INPUT);
connectToWiFi();
delay(250);
setupTime();
delay(250);
connectToMQTT();
delay(1000);
triggerCertCreation();
}
void loop() {
if (!mqttClient.connected()) {
reconnect();
} else {
digitalWrite(6, HIGH);
}
if (digitalRead(9) == LOW){
Serial.println("Sending message to get Cert topic... ");
triggerCertCreation();
}
mqttClient.loop();
delay(250);
}
将 My-ID 替换为我的帐户 ID(不带大于/小于符号)的策略。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iot:Publish",
"iot:Receive"
],
"Resource": [
"arn:aws:iot:us-east-1:<My-ID>:topic/$aws/certificates/create/json",
"arn:aws:iot:us-east-1:<My-ID>:topic/$aws/provisioning-templates/DrainAlert_FleetTemplate/provision/json"
]
},
{
"Effect": "Allow",
"Action": "iot:Subscribe",
"Resource": [
"arn:aws:iot:us-east-1:<My-ID>:topicfilter/$aws/certificates/create/*",
"arn:aws:iot:us-east-1:<My-ID>:topicfilter/$aws/provisioning-templates/DrainAlert_FleetTemplate/provision/*"
]
},
{
"Effect": "Allow",
"Action": "iot:Receive",
"Resource": [
"arn:aws:iot:us-east-1:<My-ID>:topic/$aws/certificates/create/json/accepted",
"arn:aws:iot:us-east-1:<My-ID>:topic/$aws/certificates/create/json/rejected",
"arn:aws:iot:us-east-1:<My-ID>:topic/$aws/provisioning-templates/DrainAlert_FleetTemplate/provision/json/accepted",
"arn:aws:iot:us-east-1:<My-ID>:topic/$aws/provisioning-templates/DrainAlert_FleetTemplate/provision/json/rejected"
]
}
]
}
我尝试过不订阅,因为文档说没有必要,但这两种方法都行不通。
我在 Reddit 上有一篇类似的帖子,其中有人提供了专门针对 esp32 的示例代码的链接。我的回调函数中缺少 setBufferSize,这解决了我的问题,因此现在我在 ESP32 上收到来自 AWS 的新证书信息。 示例代码