Подключение устройства к предварительно настроенному решению для удаленного мониторинга (Windows)

Общие сведения о сценарии

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

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

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

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

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

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

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

Подготовка предварительно настроенного решения для удаленного мониторинга

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

  1. Чтобы создать решение, на странице https://www.azureiotsolutions.com/ щелкните +.
  2. На панели Удаленный мониторинг щелкните Выбрать.
  3. На странице Create Remote monitoring solution (Создание решения для удаленного мониторинга) введите имя решения по своему усмотрению, выберите регион для развертывания и подписку Azure, которую нужно использовать. Затем щелкните Создать решение.
  4. Дождитесь завершения процесса подготовки.

Предупреждение

В предварительно настроенных решениях используются платные службы Azure. Закончив работу с предварительно настроенным решением, не забудьте удалить его из подписки, чтобы избежать ненужных расходов. На странице https://www.azureiotsolutions.com/ можно полностью удалить предварительно настроенное решение из подписки.

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

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

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

Примечание

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

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

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

  1. В левом нижнем углу панели мониторинга щелкните Добавить устройство.

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

  2. На панели Пользовательское устройство нажмите кнопку Добавить.

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

  3. Установите переключатель Позвольте мне определить собственный идентификатор устройства. Введите идентификатор устройства, например mydevice, и нажмите кнопку Проверить идентификатор, чтобы убедиться, что такое имя не используется. Затем нажмите кнопку Создать, чтобы подготовить устройство.

    Добавление идентификатора устройства

  4. Запишите учетные данные (идентификатор устройства, имя узла в Центре Интернета вещей и ключ устройства). Эти значения потребуются клиентскому приложению при подключении к решению для удаленного мониторинга. Затем нажмите кнопку Done(Готово).

    Просмотр учетных данных устройства

  5. Выберите устройство в списке устройств на панели мониторинга решения. Затем на панели Сведения об устройстве щелкните Включить устройство. Теперь текущее состояние устройства — Работает. Решение для удаленного мониторинга теперь может получать данные телеметрии с устройства и вызывать методы на устройстве.

Создание примера решения на C в Windows

Описанные ниже действия показывают, как создать клиентское приложение, которое взаимодействует с предварительно настроенным решением для удаленного мониторинга. Это приложение на языке C, созданное и запущенное на устройстве Windows.

Создайте начальный проект в Visual Studio 2015 или Visual Studio 2017 и добавьте клиентские пакеты NuGet для устройства Центра Интернета вещей:

  1. В Visual Studio создайте консольное приложение C, используя шаблон консольного приложения Win32 в Visual C++. Присвойте проекту имя RMDevice.

  2. На странице Параметры приложения в мастере приложений Win32 необходимо установить флажок Консольное приложение и снять флажки Предкомпилированный заголовок и Жизненный цикл разработки безопасного ПО (SDL).

  3. В обозревателе решенийудалите файлы stdafx.h, targetver.h и stdafx.cpp.

  4. В обозревателе решенийпереименуйте файл RMDevice.cpp в RMDevice.c.

  5. В обозревателе решений щелкните проект RMDevice правой кнопкой мыши и выберите пункт Управление пакетами NuGet. Щелкните Обзор, а затем найдите и установите следующие пакеты NuGet:

    • Microsoft.Azure.IoTHub.Serializer
    • Microsoft.Azure.IoTHub.IoTHubClient
    • Microsoft.Azure.IoTHub.MqttTransport.
  6. В обозревателе решений щелкните правой кнопкой мыши проект RMDevice, а затем щелкните Свойства, чтобы открыть диалоговое окно Страницы свойств проекта. Дополнительные сведения см. в статье, посвященной настройке свойств проекта Visual C++.

  7. Выберите папку Компоновщик, затем щелкните страницу свойств Входные данные.

  8. В свойство Дополнительные зависимости добавьте crypt32.lib. Нажмите кнопку ОК, а затем еще раз ОК, чтобы сохранить значения свойств проекта.

Добавьте библиотеку JSON Parson в проект RMDevice и добавьте обязательные инструкции #include:

  1. В подходящей папке на компьютере клонируйте репозиторий GitHub для Parson, используя следующую команду:

    git clone https://github.com/kgabis/parson.git
    
  2. Скопируйте файлы parson.h и parson.c из локальной копии репозитория Parson в папку проекта RMDevice.

  3. В Visual Studio щелкните правой кнопкой мыши проект RMDevice, а затем выберите Добавить > Существующий элемент.

  4. В диалоговом окне Добавление существующего элемента выберите файлы parson.h и parson.c в папке проекта RMDevice. Нажмите кнопку Добавить, чтобы добавить эти файлы в проект.

  5. В Visual Studio откройте файл RMDevice.c. Замените имеющиеся инструкции #include в этом окне следующим кодом.

    #include "iothubtransportmqtt.h"
    #include "schemalib.h"
    #include "iothub_client.h"
    #include "serializer_devicetwin.h"
    #include "schemaserializer.h"
    #include "azure_c_shared_utility/threadapi.h"
    #include "azure_c_shared_utility/platform.h"
    #include "parson.h"
    

    Примечание

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

Определение поведения устройства Интернета вещей

Клиентская библиотека сериализатора Центра Интернета вещей использует модель для указания формата сообщений, которыми устройство обменивается с Центром Интернета вещей.

  1. После операторов #include добавьте указанные ниже объявления переменных. Замените значения заполнителей [Device ID] и [Device Key] ранее записанными значениями для своего устройства, отображенными на панели мониторинга решения для удаленного мониторинга. Замените [IoTHub Name] именем узла Центра Интернета вещей, отображенным на панели мониторинга решения. Например, если имя узла Центра Интернета вещей — contoso.azure-devices.net, замените [имя_Центра_Интернета_вещей] на contoso.

    static const char* deviceId = "[Device Id]";
    static const char* connectionString = "HostName=[IoTHub Name].azure-devices.net;DeviceId=[Device Id];SharedAccessKey=[Device Key]";
    
  2. Добавьте указанный ниже код для определения модели, позволяющей устройству взаимодействовать с Центром Интернета вещей. Эта модель указывает, что устройство может выполнять следующие действия:

    • Передавать температуру, температуру окружающей среды, влажность и идентификатор устройства в виде телеметрических данных.
    • Отправлять метаданные об устройстве в Центр Интернета вещей. При запуске устройство отправляет базовые метаданные в объекте DeviceInfo.
    • Отправлять сообщаемые свойства на двойник устройства в Центре Интернета вещей. Эти сообщаемые свойства объединены в группы: конфигурация, устройство и системные свойства.
    • Получать требуемые свойства, заданные в двойнике устройства в Центре Интернета вещей, и реагировать на них.
    • Отвечать на прямые методы Reboot и InitiateFirmwareUpdate, вызываемые через портал решения. Устройство отправляет сведения о прямых методах, которые оно поддерживает, с помощью сообщаемых свойств.
    // Define the Model
    BEGIN_NAMESPACE(Contoso);
    
    /* Reported properties */
    DECLARE_STRUCT(SystemProperties,
      ascii_char_ptr, Manufacturer,
      ascii_char_ptr, FirmwareVersion,
      ascii_char_ptr, InstalledRAM,
      ascii_char_ptr, ModelNumber,
      ascii_char_ptr, Platform,
      ascii_char_ptr, Processor,
      ascii_char_ptr, SerialNumber
    );
    
    DECLARE_STRUCT(LocationProperties,
      double, Latitude,
      double, Longitude
    );
    
    DECLARE_STRUCT(ReportedDeviceProperties,
      ascii_char_ptr, DeviceState,
      LocationProperties, Location
    );
    
    DECLARE_MODEL(ConfigProperties,
      WITH_REPORTED_PROPERTY(double, TemperatureMeanValue),
      WITH_REPORTED_PROPERTY(uint8_t, TelemetryInterval)
    );
    
    /* Part of DeviceInfo */
    DECLARE_STRUCT(DeviceProperties,
      ascii_char_ptr, DeviceID,
      _Bool, HubEnabledState
    );
    
    DECLARE_DEVICETWIN_MODEL(Thermostat,
      /* Telemetry (temperature, external temperature and humidity) */
      WITH_DATA(double, Temperature),
      WITH_DATA(double, ExternalTemperature),
      WITH_DATA(double, Humidity),
      WITH_DATA(ascii_char_ptr, DeviceId),
    
      /* DeviceInfo */
      WITH_DATA(ascii_char_ptr, ObjectType),
      WITH_DATA(_Bool, IsSimulatedDevice),
      WITH_DATA(ascii_char_ptr, Version),
      WITH_DATA(DeviceProperties, DeviceProperties),
    
      /* Device twin properties */
      WITH_REPORTED_PROPERTY(ReportedDeviceProperties, Device),
      WITH_REPORTED_PROPERTY(ConfigProperties, Config),
      WITH_REPORTED_PROPERTY(SystemProperties, System),
    
      WITH_DESIRED_PROPERTY(double, TemperatureMeanValue, onDesiredTemperatureMeanValue),
      WITH_DESIRED_PROPERTY(uint8_t, TelemetryInterval, onDesiredTelemetryInterval),
    
      /* Direct methods implemented by the device */
      WITH_METHOD(Reboot),
      WITH_METHOD(InitiateFirmwareUpdate, ascii_char_ptr, FwPackageURI),
    
      /* Register direct methods with solution portal */
      WITH_REPORTED_PROPERTY(ascii_char_ptr_no_quotes, SupportedMethods)
    );
    
    END_NAMESPACE(Contoso);
    

Реализация поведения устройства

Теперь добавьте код, который будет реализовывать определенное в модели поведение.

  1. Добавьте следующие функции, которые обрабатывают требуемые свойства, заданные на панели мониторинга решения. Эти требуемые свойства определяются в модели:

    void onDesiredTemperatureMeanValue(void* argument)
    {
      /* By convention 'argument' is of the type of the MODEL */
      Thermostat* thermostat = argument;
      printf("Received a new desired_TemperatureMeanValue = %f\r\n", thermostat->TemperatureMeanValue);
    
    }
    
    void onDesiredTelemetryInterval(void* argument)
    {
      /* By convention 'argument' is of the type of the MODEL */
      Thermostat* thermostat = argument;
      printf("Received a new desired_TelemetryInterval = %d\r\n", thermostat->TelemetryInterval);
    }
    
  2. Добавьте следующие функции, которые обрабатывают прямые методы, вызываемые через Центр Интернета вещей. Эти методы определяются в модели:

    /* Handlers for direct methods */
    METHODRETURN_HANDLE Reboot(Thermostat* thermostat)
    {
      (void)(thermostat);
    
      METHODRETURN_HANDLE result = MethodReturn_Create(201, "\"Rebooting\"");
      printf("Received reboot request\r\n");
      return result;
    }
    
    METHODRETURN_HANDLE InitiateFirmwareUpdate(Thermostat* thermostat, ascii_char_ptr FwPackageURI)
    {
      (void)(thermostat);
    
      METHODRETURN_HANDLE result = MethodReturn_Create(201, "\"Initiating Firmware Update\"");
      printf("Recieved firmware update request. Use package at: %s\r\n", FwPackageURI);
      return result;
    }
    
  3. Добавьте следующую функцию, которая отправляет сообщение в предварительно настроенное решение:

    /* Send data to IoT Hub */
    static void sendMessage(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size)
    {
      IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size);
      if (messageHandle == NULL)
      {
        printf("unable to create a new IoTHubMessage\r\n");
      }
      else
      {
        if (IoTHubClient_SendEventAsync(iotHubClientHandle, messageHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
        {
          printf("failed to hand over the message to IoTHubClient");
        }
        else
        {
          printf("IoTHubClient accepted the message for delivery\r\n");
        }
    
        IoTHubMessage_Destroy(messageHandle);
      }
      free((void*)buffer);
    }
    
  4. Добавьте следующий обработчик обратных вызовов, который выполняется, когда устройство отправило новые значения сообщаемых свойств в предварительно настроенное решение:

    /* Callback after sending reported properties */
    void deviceTwinCallback(int status_code, void* userContextCallback)
    {
      (void)(userContextCallback);
      printf("IoTHub: reported properties delivered with status_code = %u\n", status_code);
    }
    
  5. Добавьте следующую функцию для подключения устройства к предварительно настроенному решению в облаке и для обмена данными. Эта функция выполняет следующие действия:

    • инициализирует платформу;
    • регистрирует пространство имен Contoso с помощью библиотеки сериализации;
    • инициализирует клиент с помощью строки подключения устройства;
    • создает экземпляр модели термостата;
    • создает и отправляет значения сообщаемых свойств;
    • отправляет объект DeviceInfo;
    • создает цикл для отправки данных телеметрии каждую секунду;
    • деинициализирует все ресурсы.
    void remote_monitoring_run(void)
    {
      if (platform_init() != 0)
      {
        printf("Failed to initialize the platform.\n");
      }
      else
      {
        if (SERIALIZER_REGISTER_NAMESPACE(Contoso) == NULL)
        {
          printf("Unable to SERIALIZER_REGISTER_NAMESPACE\n");
        }
        else
        {
          IOTHUB_CLIENT_HANDLE iotHubClientHandle = IoTHubClient_CreateFromConnectionString(connectionString, MQTT_Protocol);
          if (iotHubClientHandle == NULL)
          {
            printf("Failure in IoTHubClient_CreateFromConnectionString\n");
          }
          else
          {
    #ifdef MBED_BUILD_TIMESTAMP
            // For mbed add the certificate information
            if (IoTHubClient_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK)
            {
                printf("Failed to set option \"TrustedCerts\"\n");
            }
    #endif // MBED_BUILD_TIMESTAMP
            Thermostat* thermostat = IoTHubDeviceTwin_CreateThermostat(iotHubClientHandle);
            if (thermostat == NULL)
            {
              printf("Failure in IoTHubDeviceTwin_CreateThermostat\n");
            }
            else
            {
              /* Set values for reported properties */
              thermostat->Config.TemperatureMeanValue = 55.5;
              thermostat->Config.TelemetryInterval = 3;
              thermostat->Device.DeviceState = "normal";
              thermostat->Device.Location.Latitude = 47.642877;
              thermostat->Device.Location.Longitude = -122.125497;
              thermostat->System.Manufacturer = "Contoso Inc.";
              thermostat->System.FirmwareVersion = "2.22";
              thermostat->System.InstalledRAM = "8 MB";
              thermostat->System.ModelNumber = "DB-14";
              thermostat->System.Platform = "Plat 9.75";
              thermostat->System.Processor = "i3-7";
              thermostat->System.SerialNumber = "SER21";
              /* Specify the signatures of the supported direct methods */
              thermostat->SupportedMethods = "{\"Reboot\": \"Reboot the device\", \"InitiateFirmwareUpdate--FwPackageURI-string\": \"Updates device Firmware. Use parameter FwPackageURI to specify the URI of the firmware file\"}";
    
              /* Send reported properties to IoT Hub */
              if (IoTHubDeviceTwin_SendReportedStateThermostat(thermostat, deviceTwinCallback, NULL) != IOTHUB_CLIENT_OK)
              {
                printf("Failed sending serialized reported state\n");
              }
              else
              {
                printf("Send DeviceInfo object to IoT Hub at startup\n");
    
                thermostat->ObjectType = "DeviceInfo";
                thermostat->IsSimulatedDevice = 0;
                thermostat->Version = "1.0";
                thermostat->DeviceProperties.HubEnabledState = 1;
                thermostat->DeviceProperties.DeviceID = (char*)deviceId;
    
                unsigned char* buffer;
                size_t bufferSize;
    
                if (SERIALIZE(&buffer, &bufferSize, thermostat->ObjectType, thermostat->Version, thermostat->IsSimulatedDevice, thermostat->DeviceProperties) != CODEFIRST_OK)
                {
                  (void)printf("Failed serializing DeviceInfo\n");
                }
                else
                {
                  sendMessage(iotHubClientHandle, buffer, bufferSize);
                }
    
                /* Send telemetry */
                thermostat->Temperature = 50;
                thermostat->ExternalTemperature = 55;
                thermostat->Humidity = 50;
                thermostat->DeviceId = (char*)deviceId;
    
                while (1)
                {
                  unsigned char*buffer;
                  size_t bufferSize;
    
                  (void)printf("Sending sensor value Temperature = %f, Humidity = %f\n", thermostat->Temperature, thermostat->Humidity);
    
                  if (SERIALIZE(&buffer, &bufferSize, thermostat->DeviceId, thermostat->Temperature, thermostat->Humidity, thermostat->ExternalTemperature) != CODEFIRST_OK)
                  {
                    (void)printf("Failed sending sensor value\r\n");
                  }
                  else
                  {
                    sendMessage(iotHubClientHandle, buffer, bufferSize);
                  }
    
                  ThreadAPI_Sleep(1000);
                }
    
                IoTHubDeviceTwin_DestroyThermostat(thermostat);
              }
            }
            IoTHubClient_Destroy(iotHubClientHandle);
          }
          serializer_deinit();
        }
      }
      platform_deinit();
    }
    

    Для справки ниже приведен пример сообщения Telemetry, которое отправляется в предварительно настроенное решение.

    {"DeviceId":"mydevice01", "Temperature":50, "Humidity":50, "ExternalTemperature":55}
    

Сборка и запуск примера

Добавьте код для вызова функции remote_monitoring_run , а затем выполните сборку и запуск приложения устройства.

  1. Замените функцию main следующим кодом для вызова функции remote_monitoring_run:

    int main()
    {
      remote_monitoring_run();
      return 0;
    }
    
  2. Щелкните Построить, а затем Построить решение, чтобы выполнить сборку приложения устройства.

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

Просмотр данных телеметрии устройства на панели мониторинга

На панели мониторинга в решении для удаленного мониторинга можно просматривать данные телеметрии, отправляемые устройством в Центр Интернета вещей.

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

  2. В списке устройств отображается текущее состояние устройства — Работает. Если это не так, то на панели Сведения об устройстве щелкните Включить устройство.

    Просмотр состояния устройства

  3. Щелкните Панель мониторинга, чтобы вернуться на панель мониторинга, в раскрывающемся списке Device to View (Устройство для просмотра) выберите свое устройство, чтобы просмотреть его данные телеметрии. Телеметрия из примера приложения — 50 единиц данных о внутренней температуре, 55 единиц данных о наружной температуре и 50 единиц данных о влажности.

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

Вызов метода на устройстве

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

  1. На панели мониторинга решения для удаленного мониторинга в левой панели щелкните Устройства, чтобы перейти к списку устройств.

  2. Щелкните Идентификатор устройства для устройства в списке устройств.

  3. На панели Сведения об устройстве щелкните Методы.

    Методы устройства

  4. В раскрывающемся списке Метод выберите InitiateFirmwareUpdate, а затем в поле FWPACKAGEURI введите фиктивный URL-адрес. Щелкните Вызвать метод, чтобы вызвать метод на устройстве.

    Вызов метода устройства

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

    Просмотр журнала методов

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

В статье Настройка предварительно настроенного решения приведен ряд способов расширения этого примера. В их число входит использование реальных датчиков и реализация дополнительных команд.

Дополнительные сведения см. в статье Разрешения на сайте azureiotsuite.com.