当我发布到主题 $aws/certificates/create/json 时,为什么没有收到 $aws/certificates/create/json/accepted 或拒绝的响应?

问题描述 投票:0回答:1

我有一个 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"
      ]
    }
  ]
}

我尝试过不订阅,因为文档说没有必要,但这两种方法都行不通。

amazon-web-services aws-iot provisioning
1个回答
0
投票

我在 Reddit 上有一篇类似的帖子,其中有人提供了专门针对 esp32 的示例代码的链接。我的回调函数中缺少 setBufferSize,这解决了我的问题,因此现在我在 ESP32 上收到来自 AWS 的新证书信息。 示例代码

© www.soinside.com 2019 - 2024. All rights reserved.