Подключение к Azure IotHub с помощью MQTT в Javascript

Я продолжаю Connection refused: Not authorized при попытке подключиться к Azure IotHub с помощью MQTT.js (https://github.com/mqttjs/MQTT.js).

Пароль SAS создается с помощью Microsoft Device Explorer (https://github.com/Azure/azure-iot-sdk-csharp/tree/master/tools/DeviceExplorer), так что предоставив правильные данные о подключении для чтения / записи вместе с датой истечения срока действия в будущем, я предполагаю правильный и действительный.

Мне также требуется включить TLS / SSL (согласно документации Microsoft Azure: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support#tlsssl-configuration) через rejectUnauthorized: false ( как описано в документации для MQTT.js на странице https://github.com/mqttjs/MQTT.js#client).

Как подключиться через Javascript с помощью сторонней библиотеки MQTT и токена SAS?

Это фрагмент кода Javascript:

var MQTT = require("async-mqtt");

const deviceId = "<PUT_SOMETHING_HERE>";
const iotHubName = "<PUT_SOMETHING_HERE>";

const url = `${iotHubName}.azure-devices.net/${deviceId}/api-version=2016-11-14`;
const iotHubTopic = `devices/${deviceId}/messages/events/`

var client = MQTT.connect(`mqtts://${url}:8883`, {
  username: url,
  password: `SharedAccessSignature sr=${iotHubName}.azure-devices.net&sig=<COMBINATION_OF_PASSWORDS_URL_ENCODED>&se=<EPOCH_EXPIRY>&skn=<ACCESS_POLICY_NAME>`,
  rejectUnauthorized: false, // https://github.com/mqttjs/MQTT.js#client
});

// this is code from the MQTT.js example, but I don't even reach it
async function doStuff() {

    console.log("Starting");
    try {
        await client.publish(iotHubTopic, "It works!");
        // This line doesn't run until the server responds to the publish
        await client.end();
        // This line doesn't run until the client has disconnected without error
        console.log("Done");
    } catch (e){
        // Do something about it!
        console.log("Error while sending a message...");
        console.log(e.stack);
        process.exit();
    }
}

const ceremony = () => {
  return new Promise((resolve, reject) => {
      client.on("connect", doStuff);
      return resolve();
    })
    .then((stuff) => {
      console.log("Done?", stuff);
    })
    .catch((err) => {
      console.log("Err...", err);
      process.exit();
    });
}

ceremony();

Результат такой:

Done? undefined
events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: Connection refused: Not authorized
    at MqttClient._handleConnack (<PATH_TO_THE_JS_PROJECT>/node_modules/mqtt/lib/client.js:896:15)
    at MqttClient._handlePacket (<PATH_TO_THE_JS_PROJECT>/node_modules/mqtt/lib/client.js:332:12)
    at work (<PATH_TO_THE_JS_PROJECT>/node_modules/mqtt/lib/client.js:274:12)
    at Writable.writable._write (<PATH_TO_THE_JS_PROJECT>/node_modules/mqtt/lib/client.js:284:5)
    at doWrite (<PATH_TO_THE_JS_PROJECT>/node_modules/mqtt/node_modules/readable-stream/lib/_stream_writable.js:428:64)
    at writeOrBuffer (<PATH_TO_THE_JS_PROJECT>/node_modules/mqtt/node_modules/readable-stream/lib/_stream_writable.js:417:5)
    at Writable.write (<PATH_TO_THE_JS_PROJECT>/node_modules/mqtt/node_modules/readable-stream/lib/_stream_writable.js:334:11)
    at TLSSocket.ondata (_stream_readable.js:639:20)
    at emitOne (events.js:116:13)
    at TLSSocket.emit (events.js:211:7)

person TPPZ    schedule 06.08.2018    source источник
comment
Почему бы не использовать SDK для устройств Центра Интернета вещей? Сторонние библиотеки MQTT - это своего рода хитрость с Azure IoT Hub, поскольку это не настоящий брокер (по крайней мере, он не предназначен для такого использования).   -  person evilSnobu    schedule 06.08.2018
comment
Просто попробовал, и действительно, он выдает неаутентифицированный для MQTTS, но работает через веб-сокеты с var client = MQTT.connect(`wss://${url}`,...   -  person evilSnobu    schedule 06.08.2018
comment
Нет, заговорил слишком рано. Зависает на wss://.   -  person evilSnobu    schedule 06.08.2018
comment
@evilSnobu У меня есть требование использовать MQTT (без AMQP или других протоколов), и я пытался избежать включения кода, который я не буду использовать, например Этот пакет SDK для Центра Интернета вещей включает в себя код для разных протоколов, которые мне не нужны. Также: простой MQTT - допустимый вариант в официальной документации IoT Hub.   -  person TPPZ    schedule 06.08.2018
comment
Не обязательно. Вы могли импортировать только этот пакет: npmjs.com/package/azure-iot-device -mqtt. Для типа Message вы можете просто позаимствовать код из _ 2_ lib.   -  person evilSnobu    schedule 06.08.2018
comment
Я пытаюсь придерживаться протокола MQTT, и если я в конечном итоге использую другого брокера, я могу надеяться повторно использовать большую часть кода вместо того, чтобы начинать заново с еще одним вариантом MQTT. Согласно официальным документам Центра Интернета вещей Azure, MQTT поддерживается: docs.microsoft.com/en-us/azure/iot-hub/   -  person TPPZ    schedule 06.08.2018
comment
Это так и должно работать. Я бы открыл здесь вопрос - github.com/Azure/azure-iot-sdk-node. Если вам нужен только брокер MQTT, я бы, вероятно, просто развернул Mosquitto в 2-узловом кластере Kubernetes или что-то в этом роде.   -  person evilSnobu    schedule 06.08.2018


Ответы (2)


Да, Центр Интернета вещей Azure поддерживает MQTT, вы можете использовать протокол MQTT для прямого подключения к Центру Интернета вещей и публиковать / подписываться на темы как сообщения отправки / получения с задокументированными названиями тем и фильтрами тем. Я изменил приведенный выше код, и он отлично работает.

var MQTT = require("async-mqtt");

const deviceId = "{the device name}";
const iotHubName = "{your iot hub name}";
const userName = `${iotHubName}.azure-devices.net/${deviceId}/api-version=2016-11-14`;
const iotHubTopic = `devices/${deviceId}/messages/events/`;

var client = MQTT.connect(`mqtts://${iotHubName}.azure-devices.net:8883`, {
  keepalive: 10,
  clientId: deviceId,
  protocolId: 'MQTT',
  clean: false,
  protocolVersion: 4,
  reconnectPeriod: 1000,
  connectTimeout: 30 * 1000,
  username: userName,
  password: "{SAS Token}",
  rejectUnauthorized: false, 
});

// this is code from the MQTT.js example, but I don't even reach it
async function doStuff() {

    console.log("Starting");
    try {
        await client.publish(iotHubTopic, "It works!");
        // This line doesn't run until the server responds to the publish
        await client.end();
        // This line doesn't run until the client has disconnected without error
        console.log("Done");
    } catch (e){
        // Do something about it!
        console.log("Error while sending a message...");
        console.log(e.stack);
        process.exit();
    }
}

const ceremony = () => {
  return new Promise((resolve, reject) => {
      client.on("connect", doStuff);
      return resolve();
    })
    .then((stuff) => {
      console.log("Done?", stuff);
    })
    .catch((err) => {
      console.log("Err...", err);
      process.exit();
    });
}

ceremony();

В коде нужно отметить, что:

  1. Используйте DEVICE ID в Центре Интернета вещей в качестве clientId в параметрах подключения;
  2. Используйте протокол mqtts;
  3. Для параметра username используйте {iothubhostname} / {device_id} / api-version = 2016-11-14, где {iothubhostname} - это полное CName концентратора IoT.
  4. В поле пароль используйте токен SAS. Чтобы получить Токен SAS. Токен SAS должен быть сгенерирован с использованием политики, которая включает в себя разрешения: «запись в реестр», «подключение службы» и «подключение устройства» (комбинация меньшего числа этих трех может работать, но с предоставлением «реестра» напишите "не хватит точно).
person Michael Xu - MSFT    schedule 07.08.2018
comment
Спасибо :) но это дает Error: Connection refused: Server unavailable. - person TPPZ; 07.08.2018
comment
@TPPZ У меня работает. Проверьте свой SAS / имя пользователя. Неправильное имя пользователя также приводит к недоступности сервера для меня. - person evilSnobu; 07.08.2018
comment
@Michael Xu Какова структура используемого вами токена SAS? Какие поля определены в парах "ключ-значение"? Те же учетные данные, которые не работают для этого примера Javascript, работают вместо этого для кода Python с использованием Paho и сертификата digicert, который я скопировал из первого элемента массива в github.com/Azure/azure-iot-sdk-c/blob/master/certs/certs.c (как показано в официальных документах) - person TPPZ; 07.08.2018
comment
Хорошо, у меня это работает, используя другую политику (имя пользователя) с разными разрешениями. Кажется, должны быть предоставлены разрешения: подключение службы и подключение устройства (одно, другое или оба). Я пытался с разрешением на запись в реестр (который, я думаю, включает чтение реестра), думая, что этого было достаточно. - person TPPZ; 07.08.2018
comment
Спасибо, все работает нормально. Не могли бы вы привести пример подписки? Я не смог найти пример подписки в библиотеке async.mqtt - person Leonard AB; 10.01.2019
comment
@LeonardAB, устройство должно подписаться, используя devices/{device_id}/messages/devicebound/# в качестве фильтра тем, чтобы получать сообщения от Центра Интернета вещей. См. Общайтесь со своим Центром Интернета вещей с помощью протокола MQTT. - person Michael Xu - MSFT; 10.01.2019
comment
@ MichaelXu-MSFT спасибо. Я попытался изменить приведенный выше код, добавив его внутри doStuff: await client.publish(iotHubTopic, "It works!"); await client.subscribe(iotHubTopic2); client.on('message', function (topic, message) { console.log(message.toString()) }); await client.end(); console.log("Done");, где iotHubTopic2 равно devices/{device_id}/messages/devicebound/#. Однако на консоли ничего не отображается. Вы можете помочь? Спасибо - person Leonard AB; 11.01.2019

Я столкнулся с той же проблемой. После получасовых попыток я узнал, что один из моих коллег отключил мое устройство на Iothub.????

person Anonymous    schedule 12.08.2020