Невозможно подписаться на Azure Device Twins с помощью MQTT и ESP8266

Я работал над Azure Device Twins в течение последнего месяца. Основная цель - подписаться на три двойных пути устройства, чтобы любое изменение желаемого свойства приводило к отображению уведомления на последовательном мониторе, а желаемое свойство анализировалось и передавалось как свойство, о котором сообщается. Я запускаю код на NodeMCU, и проблема, с которой я сталкиваюсь, заключается в том, что устройство подключается к IoTHub и публикует данные, но любые изменения в двойнике устройства не отображаются и не анализируются. Двойник устройства работает, когда api-version = 2016-11-14 добавляется к имени пользователя MQTT, как только я добавляю api-версию в имя пользователя, он дает ошибку 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");
   }
}

person Imran Shafiq    schedule 13.07.2020    source источник
comment
Привет, предупреждаю, вы разместили свой общий ключ доступа. Возможно, вы захотите обновить образец кода и повторно использовать ключ.   -  person Matthijs van der Veer    schedule 13.07.2020


Ответы (1)


опубликованный вами фрагмент кода кажется неполным. Например, отсутствовал jsonDesiredProperties. Возможно, вы упустили некоторые другие вещи, но не хватает одной важной вещи - отпечатка сертификата. Центр Интернета вещей принимает только безопасные соединения MQTT, и для этого вам необходимо включить отпечаток SHA1 для Сертификат центра сертификации Microsoft.

Вы можете скачать сертификат, поместить его в файл и получить отпечаток пальца с помощью 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");
        }

Еще одно изменение, которое я внес, - это версия API, которую вы включили в свое имя пользователя MQTT. Вы можете использовать ?api-version=2018-06-30 вместо api-version=2016-11-14.

Я протестировал эти изменения на своем NodeMCU, и обновление заявленных двойных свойств работает нормально! Сообщите мне, работает ли это для вас!

person Matthijs van der Veer    schedule 14.07.2020
comment
Спасибо за ответ, я добавил отпечаток пальца, и соединение MQTT было установлено с api-версией в имени пользователя. Ошибка, которую я получаю сейчас, заключается в том, что всякий раз, когда я меняю желаемое свойство в обозревателе устройств Azure, мой обратный вызов MQTT не запускается, даже если я установил функцию обратного вызова в настройке. Я публикую свой полный код, любезно скажите мне, как заставить работать функцию обратного вызова. Спасибо - person Imran Shafiq; 14.07.2020
comment
Привет, я вижу, что ваше имя пользователя теперь HyperNet-IoF.azure-devices.net/test-device1/2018-06-30. Это должно быть HyperNet-IoF.azure-devices.net/test-device1/?api-version=2018-06-30 Я использую тот же код, что и вы, и вижу reportInterval в свойствах отчета. - person Matthijs van der Veer; 14.07.2020
comment
Спасибо за ответ, мой код теперь работает. Проблема заключалась в вопросительном знаке перед api-версией. - person Imran Shafiq; 16.07.2020
comment
Превосходно! Рад, что мой комментарий помог, я обновлю ответ, чтобы отразить и эту важную часть. Если этот ответ был полезен, не могли бы вы отметить его как принятый? Большое спасибо. - person Matthijs van der Veer; 16.07.2020