无法使用 MQTT 和 ESP8266 订阅 Azure Device Twins
Unable to subscribe to Azure Device Twins using MQTT and ESP8266
过去一个月我一直在研究 Azure Device Twins。主要目标是订阅三个设备双路径,以便所需 属性 的任何更改都会导致在串行监视器上显示通知,并且所需的 属性 被解析并作为报告 [=17] 给出=].我是 运行 NodeMCU 上的代码,我面临的问题是设备连接到 IoTHub 并发布数据,但设备孪生中的任何更改都没有显示或解析。当 api-version=2016-11-14 添加到 MQTT 用户名时,只要我在用户名它给出错误 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");
}
}
您发布的代码片段似乎不完整。例如,它缺少 jsonDesiredProperties
。您可能遗漏了一些其他内容,但缺少的一件重要内容是证书指纹。 IoT 中心仅接受安全 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");
}
我做的另一项更改是 API 您在 MQTT 用户名中包含的版本。您可以使用 ?api-version=2018-06-30
而不是 api-version=2016-11-14
.
我在我的 NodeMCU 上测试了这些更改,更新报告的孪生属性工作正常!让我知道这是否适合您!
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");
}
}
过去一个月我一直在研究 Azure Device Twins。主要目标是订阅三个设备双路径,以便所需 属性 的任何更改都会导致在串行监视器上显示通知,并且所需的 属性 被解析并作为报告 [=17] 给出=].我是 运行 NodeMCU 上的代码,我面临的问题是设备连接到 IoTHub 并发布数据,但设备孪生中的任何更改都没有显示或解析。当 api-version=2016-11-14 添加到 MQTT 用户名时,只要我在用户名它给出错误 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");
}
}
您发布的代码片段似乎不完整。例如,它缺少 jsonDesiredProperties
。您可能遗漏了一些其他内容,但缺少的一件重要内容是证书指纹。 IoT 中心仅接受安全 MQTT 连接,为此,您需要包含 Microsoft's CA cert.
您可以下载证书并将其放入文件并使用 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 上测试了这些更改,更新报告的孪生属性工作正常!让我知道这是否适合您!
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");
}
}