Подключение устройства к акселератору решения для удаленного мониторинга (Node.js)

В этом руководстве вы реализуете устройство Chiller, которое отправляет следующие данные телеметрии в акселератор решений для удаленного мониторинга:

  • температура;
  • Давление
  • влажность.

Чтобы упростить задачу, при помощи кода создаются примеры значений телеметрии для Chiller. Вы можете расширить пример, подключив к устройству физические датчики, которые будут отправлять реальные данные телеметрии.

Устройство в примере также:

  • отправляет в решение метаданные для описания его возможностей;
  • реагирует на действия, активированные на странице решения Устройства;
  • реагирует на изменения конфигурации, сведения о которых отправляются со страницы решения Устройства.

Для работы с этим руководством требуется активная учетная запись Azure. Если ее нет, можно создать бесплатную пробную учетную запись всего за несколько минут. Дополнительные сведения см. в разделе Бесплатная пробная версия Azure.

Перед началом работы

Прежде чем писать код для устройства, разверните акселератор решения для удаленного мониторинга и добавьте в решение новое реальное устройство.

Развертывание акселератора решения для удаленного мониторинга

Созданное в этом руководстве устройство Chiller отправляет данные в экземпляр акселератора решений для удаленного мониторинга. Если вы еще не подготовили этот акселератор решений в своей учетной записи Azure, изучите статью Развертывание акселератора решения для удаленного мониторинга.

После завершения развертывания решения для удаленного мониторинга нажмите кнопку Запустить, чтобы открыть панель мониторинга этого решения в браузере.

Панель мониторинга решения

Добавление устройства в решение для удаленного мониторинга

Примечание

Если вы уже добавили устройство в решение, пропустите этот шаг. Однако для следующего шага требуется строка подключения вашего устройства. Вы можете получить строку подключения устройства на портале Azure или с помощью средства CLI az iot.

Чтобы устройство смогло подключиться к акселератору решений, оно должно пройти идентификацию в Центре Интернета вещей с использованием допустимых учетных данных. При добавлении устройства в решение есть возможность сохранить строку подключения устройства, содержащую эти учетные данные. Вы добавите эту строку подключения в клиентское приложение далее в этом руководстве.

Чтобы добавить устройство в решение для удаленного мониторинга, выполните следующие действия на странице решения Обозреватель устройств:

  1. Щелкните + Новое устройство, а затем для параметра Тип устройства выберите значение Реальное:

    Добавление реального устройства

  2. Введите значение Physical-chiller в качестве идентификатора устройства. Выберите параметры Симметричный ключ и Автоматически создавать ключи:

    Выбор параметров устройства

  3. Нажмите кнопку Применить. Затем запишите значения параметров Идентификатор устройства, Первичный ключ и Строка подключения — первичный ключ:

    Получение учетных данных

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

Клиентское приложение реализует встроенную модель устройства Chiller. Модель устройства с акселератором решений указывает следующие данные устройства:

  • Сведения о свойствах, которые устройство передает в решение. Например, устройство Chiller передает сведения о своей микропрограмме и расположении.
  • Сведения о типах данных телеметрии, которые устройство отправляет в решение. Например, устройство Chiller отправляет показатели температуры, влажности и давления.
  • Сведения о методах, запуск которых можно запланировать на устройстве при помощи решения. Например, устройство Chiller должно реализовать методы Reboot, FirmwareUpdate, EmergencyValveRelease и IncreasePressure.

В этом руководстве показано, как подключить реальное устройство к акселератору решения для удаленного мониторинга. В этом руководстве используется Node.js, поэтому оно подходит для сред с минимальными ограничениями ресурсов.

Если вы предпочитаете имитацию устройства, см. раздел Создание и тестирование нового имитированного устройства.

Создание решения Node.js

Убедитесь, что на компьютере разработки установлен компонент Node.js версии 4.0.0 или более поздней. Можно запустить node --version в командной строке, чтобы проверить версию.

  1. Создайте папку с именем remotemonitoring на компьютере для разработки. Перейдите к этой папке в среде командной строки.

  2. Чтобы скачать и установить пакеты, необходимые для выполнения примера приложения, выполните следующие команды:

    npm init
    npm install async azure-iot-device azure-iot-device-mqtt --save
    
  3. В папке remotemonitoring создайте файл с именем remote_monitoring.js. Откройте этот файл в текстовом редакторе.

  4. Откройте файл remote-monitoring.js и добавьте следующие инструкции require:

    var Protocol = require('azure-iot-device-mqtt').Mqtt;
    var Client = require('azure-iot-device').Client;
    var Message = require('azure-iot-device').Message;
    var async = require('async');
    
  5. После операторов require добавьте указанные ниже объявления переменных. Замените значение заполнителя {device connection string} ранее записанным значением для своего устройства, подготовленного в решении для удаленного мониторинга:

    var connectionString = '{device connection string}';
    
  6. Чтобы определить базовые данные телеметрии, добавьте следующие переменные:

    var temperature = 50;
    var temperatureUnit = 'F';
    var humidity = 50;
    var humidityUnit = '%';
    var pressure = 55;
    var pressureUnit = 'psig';
    
  7. Чтобы определить некоторые значения свойств, добавьте следующие переменные:

    var schema = "real-chiller;v1";
    var deviceType = "RealChiller";
    var deviceFirmware = "1.0.0";
    var deviceFirmwareUpdateStatus = "";
    var deviceLocation = "Building 44";
    var deviceLatitude = 47.638928;
    var deviceLongitude = -122.13476;
    var deviceOnline = true;
    
  8. Добавьте следующую переменную, чтобы определить, какие передаваемые свойства должны отправляться в решение. Эти свойства содержат метаданные, отображаемые в пользовательском веб-интерфейсе.

    var reportedProperties = {
      "SupportedMethods": "Reboot,FirmwareUpdate,EmergencyValveRelease,IncreasePressure",
      "Telemetry": {
        [schema]: ""
      },
      "Type": deviceType,
      "Firmware": deviceFirmware,
      "FirmwareUpdateStatus": deviceFirmwareUpdateStatus,
      "Location": deviceLocation,
      "Latitude": deviceLatitude,
      "Longitude": deviceLongitude,
      "Online": deviceOnline
    }
    
  9. Добавьте следующую вспомогательную функцию для вывода результатов операции:

    function printErrorFor(op) {
        return function printError(err) {
            if (err) console.log(op + ' error: ' + err.toString());
        };
    }
    
  10. Добавьте следующую вспомогательную функцию для создания случайных значений телеметрии:

    function generateRandomIncrement() {
        return ((Math.random() * 2) - 1);
    }
    
  11. Добавьте приведенную ниже общую функцию для обработки вызовов прямого метода из решения. Функция отвечает за отображение сведений о вызванном прямом методе. В этом примере ее использование не приводит к каким-либо изменениям устройства. Решение использует прямые методы для выполнения действий на устройствах:

    function onDirectMethod(request, response) {
      // Implement logic asynchronously here.
      console.log('Simulated ' + request.methodName);
    
      // Complete the response
      response.send(200, request.methodName + ' was called on the device', function (err) {
        if (err) console.error('Error sending method response :\n' + err.toString());
        else console.log('200 Response to method \'' + request.methodName + '\' sent successfully.');
      });
    }
    
  12. Добавьте приведенную ниже функцию для обработки вызовов прямого метода FirmwareUpdate из решения. Функция отвечает за проверку параметров, переданных в полезные данные прямого метода, и асинхронный запуск моделирования для обновления встроенного ПО:

    function onFirmwareUpdate(request, response) {
      // Get the requested firmware version from the JSON request body
      var firmwareVersion = request.payload.Firmware;
      var firmwareUri = request.payload.FirmwareUri;
    
      // Ensure we got a firmware values
      if (!firmwareVersion || !firmwareUri) {
        response.send(400, 'Missing firmware value', function(err) {
          if (err) console.error('Error sending method response :\n' + err.toString());
          else console.log('400 Response to method \'' + request.methodName + '\' sent successfully.');
        });
      } else {
        // Respond the cloud app for the device method
        response.send(200, 'Firmware update started.', function(err) {
          if (err) console.error('Error sending method response :\n' + err.toString());
          else {
            console.log('200 Response to method \'' + request.methodName + '\' sent successfully.');
    
            // Run the simulated firmware update flow
            runFirmwareUpdateFlow(firmwareVersion, firmwareUri);
          }
        });
      }
    }
    
  13. Добавьте следующую функцию для моделирования длительного потока обновления встроенного ПО с передачей в решение сведений о ходе выполнения:

    // Simulated firmwareUpdate flow
    function runFirmwareUpdateFlow(firmwareVersion, firmwareUri) {
      console.log('Simulating firmware update flow...');
      console.log('> Firmware version passed: ' + firmwareVersion);
      console.log('> Firmware URI passed: ' + firmwareUri);
      async.waterfall([
        function (callback) {
          console.log("Image downloading from " + firmwareUri);
          var patch = {
            FirmwareUpdateStatus: 'Downloading image..'
          };
          reportUpdateThroughTwin(patch, callback);
          sleep(10000, callback);
        },
        function (callback) {
          console.log("Downloaded, applying firmware " + firmwareVersion);
          deviceOnline = false;
          var patch = {
            FirmwareUpdateStatus: 'Applying firmware..',
            Online: false
          };
          reportUpdateThroughTwin(patch, callback);
          sleep(8000, callback);
        },
        function (callback) {
          console.log("Rebooting");
          var patch = {
            FirmwareUpdateStatus: 'Rebooting..'
          };
          reportUpdateThroughTwin(patch, callback);
          sleep(10000, callback);
        },
        function (callback) {
          console.log("Firmware updated to " + firmwareVersion);
          deviceOnline = true;
          var patch = {
            FirmwareUpdateStatus: 'Firmware updated',
            Online: true,
            Firmware: firmwareVersion
          };
          reportUpdateThroughTwin(patch, callback);
          callback(null);
        }
      ], function(err) {
        if (err) {
          console.error('Error in simulated firmware update flow: ' + err.message);
        } else {
          console.log("Completed simulated firmware update flow");
        }
      });
    
      // Helper function to update the twin reported properties.
      function reportUpdateThroughTwin(patch, callback) {
        console.log("Sending...");
        console.log(JSON.stringify(patch, null, 2));
        client.getTwin(function(err, twin) {
          if (!err) {
            twin.properties.reported.update(patch, function(err) {
              if (err) callback(err);
            });      
          } else {
            if (err) callback(err);
          }
        });
      }
    
      function sleep(milliseconds, callback) {
        console.log("Simulate a delay (milleseconds): " + milliseconds);
        setTimeout(function () {
          callback(null);
        }, milliseconds);
      }
    }
    
  14. Добавьте приведенный ниже код для отправки данных телеметрии в решение. Клиентское приложение добавляет свойства в сообщение, чтобы определить его схему:

    function sendTelemetry(data, schema) {
      if (deviceOnline) {
        var d = new Date();
        var payload = JSON.stringify(data);
        var message = new Message(payload);
        message.properties.add('iothub-creation-time-utc', d.toISOString());
        message.properties.add('iothub-message-schema', schema);
    
        console.log('Sending device message data:\n' + payload);
        client.sendEvent(message, printErrorFor('send event'));
      } else {
        console.log('Offline, not sending telemetry');
      }
    }
    
  15. Добавьте следующий код для создания экземпляра клиента:

    var client = Client.fromConnectionString(connectionString, Protocol);
    
  16. Добавьте следующий код, который:

    • открывает подключение;

    • настраивает обработчик для требуемых свойств;

    • отправляет сообщаемые свойства;

    • регистрирует обработчики для прямых методов; В примере используется отдельный обработчик для прямого метода обновления встроенного ПО.

    • начинает отправку данных телеметрии.

      client.open(function (err) {
      if (err) {
        printErrorFor('open')(err);
      } else {
        // Create device Twin
        client.getTwin(function (err, twin) {
          if (err) {
            console.error('Could not get device twin');
          } else {
            console.log('Device twin created');
      
            twin.on('properties.desired', function (delta) {
              // Handle desired properties set by solution
              console.log('Received new desired properties:');
              console.log(JSON.stringify(delta));
            });
      
            // Send reported properties
            twin.properties.reported.update(reportedProperties, function (err) {
              if (err) throw err;
              console.log('Twin state reported');
            });
      
            // Register handlers for all the method names we are interested in.
            // Consider separate handlers for each method.
            client.onDeviceMethod('Reboot', onDirectMethod);
            client.onDeviceMethod('FirmwareUpdate', onFirmwareUpdate);
            client.onDeviceMethod('EmergencyValveRelease', onDirectMethod);
            client.onDeviceMethod('IncreasePressure', onDirectMethod);
          }
        });
      
        // Start sending telemetry
        var sendDeviceTelemetry = setInterval(function () {
          temperature += generateRandomIncrement();
          pressure += generateRandomIncrement();
          humidity += generateRandomIncrement();
          var data = {
            'temperature': temperature,
            'temperature_unit': temperatureUnit,
            'humidity': humidity,
            'humidity_unit': humidityUnit,
            'pressure': pressure,
            'pressure_unit': pressureUnit
          };
          sendTelemetry(data, schema)
        }, 5000);
      
        client.on('error', function (err) {
          printErrorFor('client')(err);
          if (sendTemperatureInterval) clearInterval(sendTemperatureInterval);
          if (sendHumidityInterval) clearInterval(sendHumidityInterval);
          if (sendPressureInterval) clearInterval(sendPressureInterval);
          client.close(printErrorFor('client.close'));
        });
      }
      });
      
  17. Сохраните изменения в файле remote_monitoring.js.

  18. Чтобы запустить пример приложения, выполните следующую команду в командной строке:

    node remote_monitoring.js
    

Просмотр телеметрии устройства

Вы можете просмотреть данные телеметрии, отправленные с устройства, на странице Обозреватель устройств в решении.

  1. Выберите подготовленное устройство в списке устройств на странице Обозреватель устройств. На панели отображаются сведения об устройстве, включая график телеметрии устройства:

    Просмотр сведений об устройстве

  2. Выберите Pressure (Давление) для изменения порядка отображения телеметрии:

    Просмотр телеметрии по давлению

  3. Чтобы просмотреть диагностические сведения об устройстве, прокрутите вниз до раздела Diagnostics (Диагностика):

    Просмотр диагностики устройства

Действия на устройстве

Для вызова методов на устройствах используйте страницу Обозреватель устройств в решении для удаленного мониторинга. Например, в устройствах решения для удаленного мониторинга Chiller реализован метод перезагрузки.

  1. Выберите Устройства для перехода к странице Обозреватель устройств в решении.

  2. Выберите подготовленное устройство в списке устройств на странице Обозреватель устройств:

    Выбор реального устройства

  3. Чтобы отобразить список методов, которые можно вызвать на устройстве, выберите Задания > Методы. Чтобы запланировать выполнение задания на нескольких устройствах, можно выбрать несколько устройств в списке. На панели Jobs (Задания) отображаются типы метода, который является общим для всех выбранных устройств.

  4. Выберите Перезагрузка, задайте имя задания RebootPhysicalChiller и щелкните Применить:

    Планирование обновления встроенного ПО

  5. Когда имитированное устройство обрабатывает метод, в консоли отображается последовательность сообщений о выполнении кода устройства.

Примечание

Для отслеживания состояния задания в решении выберите Просмотреть состояние задания.

Дальнейшие действия

Способы настройки акселератора решений описаны в статье Настройка акселератора решения для удаленного мониторинга.