【问题标题】:Unable to subscribe to Azure Device Twins using MQTT and ESP8266无法使用 MQTT 和 ESP8266 订阅 Azure 设备孪生
【发布时间】:2020-07-13 08:47:22
【问题描述】:

上个月我一直在研究 Azure 设备孪生。主要目标是订阅三个设备孪生路径,以便所需属性的任何更改都会导致在串行监视器上显示通知,并且所需属性被解析并作为报告属性给出。我在 NodeMCU 上运行代码,我面临的问题是设备连接到 IoTHub 并发布数据,但未显示或解析设备孪生中的任何更改。当 api-version=2016-11-14 添加到 MQTT 用户名时,Device Twin 工作,只要我在用户名中添加 api-version,它就会给出错误 failed rc=-1。我正在使用的代码如下所示

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <WiFiClientSecure.h>
const char mqtt_client[] = "test-device1";
const char mqtt_server[] = "HyperNet-IoTHub-Azure-Sphere.azure-devices.net";
const int mqtt_port = 8883;
const char mqtt_user[] = "HyperNet-IoTHub-Azure-Sphere.azure-devices.net/test-device1/api-version=2016-11-14";


void callback(char* topic, byte* payload, unsigned int length);

WiFiClientSecure WiFiclient;
PubSubClient client(WiFiclient);
void callback(char* topic, byte* payload, unsigned int length);
void parseDesiredProperties(byte* payload);

unsigned long previousMillis = 0;
long interval = 5000;
void reconnect();

void setup(){
  Serial.begin(9600);
  delay(250);
  client.setServer(mqtt_server, 8883);
  client.setCallback(callback);
  WiFi.disconnect();
  delay(100);
  WiFi.mode(WIFI_STA);
  Serial.println("Connecting To Wi-Fi: " + String(ssid));
  WiFi.begin(ssid,pass);
  while(WiFi.status() !=WL_CONNECTED){
    delay(500);
    Serial.print("..");
  }
  Serial.println(" ");
  Serial.println("Wi-Fi Connected");
}

void loop(){
  if(!client.connected()){
    reconnect();
  }
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval){
    previousMillis = currentMillis;
    float value1 = 12.3;
    float value2 = 13.6;
    String postData = "{\"testvalue1\":" + String(value1) + ",\"testvalue2\":" + String(value2) +"}";
    char postBuffer[postData.length()+1];
    postData.toCharArray(postBuffer, postData.length()+1);
    Serial.println(postBuffer);
    client.publish("devices/test-device1/messages/events/", postBuffer);
  }

  client.loop();

}

void reconnect(){
  WiFiclient.setInsecure();
  while(!client.connected()){
    Serial.println("Attempting MQTT Connection");
    if (client.connect(mqtt_client, mqtt_user, mqtt_pass)) {
      Serial.println("connected");
      client.subscribe("devices/test-device1/messages/devicebound/#");
      // subscribe to operation responses
      client.subscribe("$iothub/twin/res/#");
      // subscribe to desired property updates
      client.subscribe("$iothub/twin/PATCH/properties/desired/#");
    } 
    else {
     Serial.print("failed, rc=");
     Serial.print(client.state());
     Serial.println(" try again in 5 seconds");
     delay(5000);
    }  
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("MQTT message arrived on topic: ");
  Serial.println(topic);
  if (String(topic).startsWith("$iothub/twin/PATCH/properties/desired")) {
    parseDesiredProperties(payload);  
  }   
}

void parseDesiredProperties(byte* payload) {

  JsonObject& root = jsonDesiredProperties.parseObject(payload);
  if(root.success()) {
    Serial.println("Parsed desired properties");
    int newMillis=root["reportInterval"];
    if(newMillis > 2999 && newMillis < 120001) {
      interval = newMillis;
      String postProperty = "{\"reportInterval\":" + String(newMillis) + "}";
      char postBuffer[postProperty.length()+1];
      postProperty.toCharArray(postBuffer, postProperty.length()+1);
      client.publish("$iothub/twin/PATCH/properties/reported/?$rid=1", postBuffer);
      Serial.print("Set new interval to: ");
      Serial.println(newMillis);
    }
   } 
   else {
    Serial.println("Could not parse desired properties");
   }
}

【问题讨论】:

  • 您好,请注意,您发布了共享访问密钥。您可能想要更新您的代码示例并重新滚动您的密钥。

标签: azure mqtt azure-iot-hub arduino-esp8266 azure-management-api


【解决方案1】:

您发布的代码 sn-p 似乎不完整。例如,它缺少jsonDesiredProperties。您可能遗漏了其他一些东西,但缺少的一件重要的事情是证书指纹。 IoT Hub 仅接受安全 MQTT 连接,为此,您需要包含 Microsoft's CA cert 的 SHA1 指纹。

您可以下载证书并将其放入文件中,然后使用 openssl 检索指纹:

openssl x509 -noout -fingerprint -sha1 -inform pem -in [certificate-file.crt]

然后您的设置方法可以包括指纹:

static const char *fingerprint PROGMEM = "D4 DE 20 D0 5E 66 FC 53 FE 1A 50 88 2C 78 DB 28 52 CA E4 74";

    void setup(){
          Serial.begin(9600);
          delay(250);
          WiFiclient.setFingerprint(fingerprint);
        
          client.setServer(mqtt_server, 8883);
          client.setCallback(callback);
          WiFi.disconnect();
          delay(100);
          WiFi.mode(WIFI_STA);
          Serial.println("Connecting To Wi-Fi");
          WiFi.begin("<REDACTED>","<REDACTED>");
          while(WiFi.status() !=WL_CONNECTED){
            delay(500);
            Serial.print("..");
          }
          Serial.println(" ");
          Serial.println("Wi-Fi Connected");
        }

我所做的另一项更改是您在 MQTT 用户名中包含的 API 版本。您可以使用?api-version=2018-06-30 而不是api-version=2016-11-14

我在我的 NodeMCU 上测试了这些更改,更新报告的孪生属性运行良好!让我知道这是否适合您!

【讨论】:

  • 感谢您的回答,我添加了指纹并使用用户名中的 api-version 建立了 MQTT 连接。我现在得到的错误是,每当我从 azure 设备资源管理器更改所需的属性时,即使我在设置中设置了回调函数,我的 MQTT 回调也不会运行。我正在发布我的完整代码,请告诉我如何使回调函数工作。谢谢
  • 嘿,我看到你的用户名现在是HyperNet-IoF.azure-devices.net/test-device1/2018-06-30。应该是 HyperNet-IoF.azure-devices.net/test-device1/?api-version=2018-06-30 我现在运行的代码和你一样,我在报告的属性中看到了 reportInterval。
  • 感谢您的回复,我的代码现在可以使用了。问题是 api-version 之前的问号。
  • 太棒了!很高兴我的评论有所帮助,我将更新答案以反映这一重要部分。如果此答案有用,您能否将其标记为已接受?非常感谢。
【解决方案2】:
DynamicJsonBuffer jsonDesiredProperties;
char ssid[] = "Imran's Phone";
char pass[] = "1234567890";
int status = WL_IDLE_STATUS;

const char mqtt_client[] = "test-device1";
const char mqtt_server[] = "Hypernet-IOF.azure-devices.net";
const int mqtt_port = 8883;
const char mqtt_user[] = "HyperNet-IoF.azure-devices.net/test-device1/2018-06-30";

static const char *fingerprint PROGMEM = "D4 DE 20 D0 5E 66 FC 53 FE 1A 50 88 2C 78 DB 
28 52 CA E4 74";
void callback(char* topic, byte* payload, unsigned int length);

WiFiClientSecure WiFiclient;
PubSubClient client(WiFiclient);
void callback(char* topic, byte* payload, unsigned int length);
void parseDesiredProperties(byte* payload);

unsigned long previousMillis = 0;
long interval = 5000;
void reconnect();

void setup(){
  Serial.begin(9600);
  delay(250);
  WiFiclient.setFingerprint(fingerprint);
  client.setServer(mqtt_server, 8883);
  client.setCallback(callback);
  WiFi.disconnect();
  delay(100);
  WiFi.mode(WIFI_STA);
  Serial.println("Connecting To Wi-Fi: " + String(ssid));
  WiFi.begin(ssid,pass);
  while(WiFi.status() !=WL_CONNECTED){
    delay(500);
    Serial.print("..");
  }
  Serial.println(" ");
  Serial.println("Wi-Fi Connected");
}

void loop(){
  if(!client.connected()){
    reconnect();
  }
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval){
    previousMillis = currentMillis;
    float value1 = 12.3;
    float value2 = 13.6;
    String postData = "{\"testvalue1\":" + String(value1) + ",\"testvalue2\":" + 
String(value2) +"}";
    char postBuffer[postData.length()+1];
    postData.toCharArray(postBuffer, postData.length()+1);
    Serial.println(postBuffer);
    client.publish("devices/test-device1/messages/events/", postBuffer);
  }

  client.loop();

}

 void reconnect(){
  WiFiclient.setInsecure();
  while(!client.connected()){
    Serial.println("Attempting MQTT Connection");
    if (client.connect(mqtt_client, mqtt_user, mqtt_pass)) {
      Serial.println("connected");
      client.subscribe("devices/test-device1/messages/devicebound/#");
      // subscribe to operation responses
       client.subscribe("$iothub/twin/res/#");
      // subscribe to desired property updates
      client.subscribe("$iothub/twin/PATCH/properties/desired/#");
    } 
    else {
     Serial.print("failed, rc=");
     Serial.print(client.state());
     Serial.println(" try again in 5 seconds");
     delay(5000);
    }  
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("MQTT message arrived on topic: ");
  Serial.println(topic);
  if (String(topic).startsWith("$iothub/twin/PATCH/properties/desired")) {
    parseDesiredProperties(payload);  
  }   
}

void parseDesiredProperties(byte* payload) {

  JsonObject& root = jsonDesiredProperties.parseObject(payload);
  if(root.success()) {
    Serial.println("Parsed desired properties");
    int newMillis=root["reportInterval"];
    if(newMillis > 2999 && newMillis < 120001) {
  interval = newMillis;
  String postProperty = "{\"reportInterval\":" + String(newMillis) + "}";
  char postBuffer[postProperty.length()+1];
  postProperty.toCharArray(postBuffer, postProperty.length()+1);
  client.publish("$iothub/twin/PATCH/properties/reported/?$rid=1", postBuffer);
  Serial.print("Set new interval to: ");
  Serial.println(newMillis);
}
   } 
   else {
    Serial.println("Could not parse desired properties");
   }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多