Отправка сообщений с конечного устройства. Устройство нисходящего потока, не обрабатываемое IoT Edge, работающим на прозрачном шлюзе.

Я выполнил все инструкции по настройке «нисходящего устройства» для отправки сообщений через IoT Edge, работающий в прозрачном шлюзе. Я считаю, что мои правила маршрутизации верны, но мой функциональный модуль не получает никаких сообщений через поток сообщений.

Я выполнил следующие инструкции: https://docs.microsoft.com/en-us/azure/iot-edge/how-to-create-transparent-gateway-linux

Я использую 2 виртуальные машины Linxu (ubuntu 16.04.5).

  1. Виртуальная машина прозрачного шлюза IoT Edge настроена со всеми правильно настроенными, настроенными и проверенными сертификатами. Я смог использовать инструмент openssl из

openssl s_client -connect {my-gateway-machine-name-dns-name} .centralus.cloudapp.azure.com: 8883 -CAfile /certs/certs/azure-iot-test-only.root.ca.cert.pem - шоуцерты

  1. Нисходящее устройство, работающее на виртуальной машине Linux с установленными и проверенными сертификатами. Моя строка подключения выглядит следующим образом:

    HostName = {IoTHubName} .azure-devices.net; DeviceId = TC51_EdgeDownStreamDevice01; SharedAccessKey = {My-Shared-Access-Key} = GatewayHostName = {my-gateway-machine-name-dns-name} .centralus.cloudapp.azure. ком

а. Я подтвердил, что получил успешную проверку сертификата SSL с помощью инструмента openssl. б. Я использую следующее на своем нисходящем устройстве для моего подключения с помощью NodeJS SDK

var client = DeviceClient.fromConnectionString (connectionString, Mqtt); c. Я вижу сообщения, появляющиеся в Azure IoT Hub в облаке, но я не могу запустить мой модуль на прозрачном шлюзе IoT Edge, чтобы он был поражен.

  1. Вот мои правила маршрутизации, настроенные для edgeHub, как указано в разделе «Маршрутизация сообщений от нижестоящих устройств» на странице образца документа.

Вот что показано в примерах документов: {"routes": {"sensorToAIInsightsInput1": "FROM / messages / * ГДЕ НЕ IS_DEFINED ($ connectionModuleId) INTO BrokeredEndpoint (\" / modules / ai_insights / inputs / input1 \ ")", " AIInsightsToIoTHub ":" FROM / messages / modules / ai_insights / output / output1 INTO $ upstream "}}

Это то, что установлено в моей конфигурации маршрутизации: "routes": {"downstreamBatterySensorToBatteryDataFunctionInput1": "FROM / * WHERE NOT IS_DEFINED ($ connectionModuleId) INTO BrokeredEndpoint (\" / modules / BatteryDataFunctionModule / inputs / input1 \ ")", "BatteryDodule ":" FROM / messages / modules / BatteryDataFunctionModule / output / * INTO $ upstream "}

** Обратите внимание, что я использовал «FROM / * WHERE NOT IS_DEFINED» и «FROM / messages / * WHERE NOT IS_DEFINED»

  1. Мой модуль на IoT Edge настроен как функция. Когда я использую готовый пример, в котором имитатор является другим модулем, работающим на IoT Edge, моя функция выполняется правильно. Модуль не запускается только тогда, когда я пытаюсь использовать «Нисходящее устройство».

Я включил «Ведение журнала отладки для службы IoT Edge» на моем прозрачном шлюзе.

This is the basic Run method for the Function module:

#r "Microsoft.Azure.Devices.Client"
#r "Newtonsoft.Json"

using System.IO;
using Microsoft.Azure.Devices.Client;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

// Filter messages based on the temperature value in the body of the     message and the temperature threshold value.
public static async Task Run(Message messageReceived, IAsyncCollector<Message> output, TraceWriter log)
{

Как я могу выяснить, как заставить мой модуль, работающий в IoT Edge, запускаться / запускаться с нисходящего устройства?


person Chris Langston    schedule 18.09.2018    source источник


Ответы (2)


Итак, вы говорите, что видите сообщения в Центре Интернета вещей, но не в Edge ... Пара вещей:

вы разместили это как строку подключения в приложении узла: HostName = {IoTHubName} .azure-devices.net; DeviceId = TC51_EdgeDownStreamDevice01; SharedAccessKey = {My-Shared-Access-Key} = GatewayHostName = {my-gateway-machine-name -dns-name} .centralus.cloudapp.azure.com

Вы именно это скопировали / вставили? Причина, по которой я спрашиваю, заключается в том, что между общим ключом доступа и словом "GatewayHostName" стоит знак равенства, а не точка с запятой ..

это должно быть: HostName = {IoTHubName} .azure-devices.net; DeviceId = TC51_EdgeDownStreamDevice01; SharedAccessKey = {My-Shared-Access-Key}; GatewayHostName = {my-gateway-machine-name-dns-name} .centralus. cloudapp.azure.com

(обратите внимание на ';' перед GatewayHostName ... если бы у вас действительно был знак равенства вместо точки с запятой, невозможно сказать, какой хаос это вызовет :-)

Во-вторых, в своем маршруте вы вызываете свой модуль BatteryDataFunctionModule ... просто хотите убедиться, что имя модуля является точным, в том числе с учетом регистра. Вы, наверное, знаете это, но не хотите предполагать ..

Наконец, если две вещи, указанные выше, проверяются, можете ли вы добавить дополнительный маршрут отладки, который также отправляет «входящие данные» в IoTHub ..
«FROM / * WHERE NOT IS_DEFINED ($ connectionModuleId) INTO $ upstream»

так что мы можем убедиться, что сообщения действительно проходят через iot edge.

person Steve Busby - MSFT    schedule 19.09.2018
comment
Кстати, я хотел добавить к своему ответу выше, что, поскольку вы говорите, что видите данные, отображаемые в IoT Hub, но не в IoT Edge, и судя по тому, что у вас нет маршрута, который должен направлять данные вашего устройства непосредственно в IoTHub (только для вашего модуля), что наличие знака равенства в строке подключения приводит к неправильному синтаксическому анализу ... поэтому я предполагаю, что из-за этого параметр GatewayHostName игнорируется и что клиент узла по умолчанию просто , разговаривая напрямую с IoT Hub и даже не пытаясь добраться до IoT Edge. - person Steve Busby - MSFT; 19.09.2018
comment
@ steve-busby-msft, мне действительно не хватало; точка с запятой. Я внес это изменение, но по-прежнему не вижу, чтобы сообщения попадали под действие моих правил маршрутизации. Я также добавил дополнительную маршрутизацию, о которой вы упомянули, и она не перехватывает мои сообщения и не отправляет их в Центр Интернета вещей. - person Chris Langston; 20.09.2018
comment
@ Стив-Басби-MSFT. Кроме того, когда я запускаю модуль на своем устройстве IoTEdge (как тот, который поставляется со всеми образцами), используя правила маршрутизации по умолчанию, мой функциональный модуль запускается каждый раз без каких-либо проблем. tempSensor: {версия: 1.0, тип: docker, status: running, restartPolicy: always, settings: {image: mcr.microsoft.com/azureiotedge-simulated-temperature-sensor:1.0, createOptions:}}, - person Chris Langston; 20.09.2018
comment
маршруты: {sensorToBatteryDataFunctionModule: FROM / messages / modules / tempSensor / output / temperatureOutput INTO BrokeredEndpoint (\ / modules / BatteryDataFunctionModule / inputs / input1 \), debuggingRoute: FROM / * WHERE NOT IS_DEFINED ($ connectionModuleSensorData: downstreamBattery: $ connectionModuleIdata) INTO $ / * ГДЕ НЕ IS_DEFINED ($ connectionModuleId) INTO BrokeredEndpoint (\ / modules / BatteryDataFunctionModule / inputs / input1 \), BatteryDataFunctionModuleToIoTHub: FROM / messages / modules / BatteryDataFunctionModule / output / * INTO $ upstream} - person Chris Langston; 20.09.2018
comment
Я внес все изменения и не могу передать сообщения через устройство IoT Edge. Что еще я могу попробовать? Если я удалю GatewayHostName из строки подключения нижестоящего устройства, мои сообщения попадут в IoT Hub без проблем, но я считаю, что это полностью обходит IoTEdge. - person Chris Langston; 20.09.2018
comment
Привет, Крис ... еще одна вещь, которую стоит попробовать ... когда я маршрутизирую листовые устройства в модули, я использую FROM / messages / * WHERE NOT IS_DEFINED ($ connectionModuleId) INTO ... в качестве первой части спецификации маршрута . Обратите внимание на / messages / * и просто / * - person Steve Busby - MSFT; 21.09.2018
comment
Пример предыдущего (и хороший пример для Edge в целом) можно найти в наборе практических занятий, которые я поддерживаю здесь - ›github.com/AzureIoTGBB/azure-iot-edge-hol-linux (я впервые представляю этот маршрут в нижней части модуля 3) - person Steve Busby - MSFT; 21.09.2018
comment
Привет, Стив. Вы создали фантастическую практическую лабораторию! Мне жаль, что я не нашел это раньше :-) Я предлагаю сослаться на эти документы из Transparent Gateway. Я закончил тем, что создал .NET Core Downstream / Leaf Device вместо NodeJS, используя базовые примеры загрузки поля CA уровня приложения в приложение, и все мои сообщения правильно поступают в IoT Edge, попадая во все правила маршрутизации. Я думаю, что в NodeJS SDK должна быть проблема. - person Chris Langston; 21.09.2018
comment
рад, что вы нашли эти лабораторные работы полезными ... У меня есть версия для Windows, которую мне нужно обновить для битов GA, и я работаю над версией Raspberry Pi ... В эти выходные я хотел ответить, что Node не уважает и победил ' t читать сертификаты из хранилища сертификатов и что вы должны явно указать ему путь, но, похоже, снизу вы сами это поняли. Хорошая работа. - person Steve Busby - MSFT; 25.09.2018

Есть 2 проблемы, которые необходимо решить, чтобы установить соединение с нисходящим устройством.

  1. Благодаря @ Steve-Busby-Msft мне нужно было поставить точку с запятой (;) в конце SharedAccessKey и перед GatewayHostName

вы разместили это как строку подключения в приложении узла: HostName = {IoTHubName} .azure-devices.net; DeviceId = TC51_EdgeDownStreamDevice01; SharedAccessKey = {My-Shared-Access-Key} = GatewayHostName = {my-gateway-machine-name -dns-name} .centralus.cloudapp.azure.com

  1. Приложение NodeJS Downstream Device также должно правильно загрузить сертификат на «уровне приложения».

Обратите внимание на раздел кода для

var edge_ca_cert_path = '[Путь к сертификату пограничного CA]';

Узловое приложение JS Downstream

'use strict';

var fs = require('fs');
var Protocol = require('azure-iot-device-mqtt').Mqtt;
// Uncomment one of these transports and then change it in fromConnectionString to test other transports
// var Protocol = require('azure-iot-device-http').Http;
// var Protocol = require('azure-iot-device-amqp').Amqp;
var Client = require('azure-iot-device').Client;
var Message = require('azure-iot-device').Message;

// 1) Obtain the connection string for your downstream device and to it
//    append this string GatewayHostName=<edge device hostname>;
// 2) The edge device hostname is the hostname set in the config.yaml of the Edge device
//    to which this sample will connect to.
//
// The resulting string should look like the following
//  "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>;GatewayHostName=<edge device hostname>"
var connectionString = '[Downstream device IoT Edge connection string]';

// Path to the Edge "owner" root CA certificate
var edge_ca_cert_path = '[Path to Edge CA certificate]';

// fromConnectionString must specify a transport constructor, coming from any transport package.
var client = Client.fromConnectionString(connectionString, Protocol);

var connectCallback = function (err) {
  if (err) {
    console.error('Could not connect: ' + err.message);
  } else {
    console.log('Client connected');
    client.on('message', function (msg) {
      console.log('Id: ' + msg.messageId + ' Body: ' + msg.data);
      // When using MQTT the following line is a no-op.
      client.complete(msg, printResultFor('completed'));
      // The AMQP and HTTP transports also have the notion of completing, rejecting or abandoning the message.
      // When completing a message, the service that sent the C2D message is notified that the message has been processed.
      // When rejecting a message, the service that sent the C2D message is notified that the message won't be processed by the device. the method to use is client.reject(msg, callback).
      // When abandoning the message, IoT Hub will immediately try to resend it. The method to use is client.abandon(msg, callback).
      // MQTT is simpler: it accepts the message by default, and doesn't support rejecting or abandoning a message.
    });

    // Create a message and send it to the IoT Hub every second
    var sendInterval = setInterval(function () {
      var windSpeed = 10 + (Math.random() * 4); // range: [10, 14]
      var temperature = 20 + (Math.random() * 10); // range: [20, 30]
      var humidity = 60 + (Math.random() * 20); // range: [60, 80]
      var data = JSON.stringify({ deviceId: 'myFirstDownstreamDevice', windSpeed: windSpeed, temperature: temperature, humidity: humidity });
      var message = new Message(data);
      message.properties.add('temperatureAlert', (temperature > 28) ? 'true' : 'false');
      console.log('Sending message: ' + message.getData());
      client.sendEvent(message, printResultFor('send'));
    }, 2000);

    client.on('error', function (err) {
      console.error(err.message);
    });

    client.on('disconnect', function () {
      clearInterval(sendInterval);
      client.removeAllListeners();
      client.open(connectCallback);
    });
  }
};

// Provide the Azure IoT device client via setOptions with the X509
// Edge root CA certificate that was used to setup the Edge runtime
var options = {
  ca : fs.readFileSync(edge_ca_cert_path, 'utf-8'),
};

client.setOptions(options, function(err) {
  if (err) {
    console.log('SetOptions Error: ' + err);
  } else {
    client.open(connectCallback);
  }
});
person Chris Langston    schedule 24.09.2018