Conectar seu dispositivo à solução pré-configurada de monitoramento remoto (Windows)
Visão geral do cenário
Nesse cenário, você cria um dispositivo que envia a telemetria a seguir para a solução pré-configurada de monitoramento remoto:
- Temperatura externa
- Temperatura interna
- Umidade
Para simplificar, o código no dispositivo gera valores de exemplo, mas é recomendável estender o exemplo conectando sensores reais aos dispositivos e enviando telemetria real.
O dispositivo também é capaz de responder aos métodos invocados no painel da solução e aos conjuntos de valores de propriedade desejada no painel da solução.
Para concluir este tutorial, você precisa de uma conta ativa do Azure. Se não tiver uma conta, você poderá criar uma conta de avaliação gratuita em apenas alguns minutos. Para obter detalhes, consulte Avaliação gratuita do Azure.
Antes de começar
Antes de escrever qualquer código para o seu dispositivo, você precisa provisionar a solução pré-configurada de monitoramento remoto e provisionar um novo dispositivo personalizado nessa solução.
Provisionar sua solução pré-configurada de monitoramento remoto
O dispositivo que você criar neste tutorial enviará dados a uma instância da solução pré-configurada de monitoramento remoto. Se você ainda não provisionou a solução pré-configurada de monitoramento remoto em sua conta do Azure, use as seguintes etapas:
- Na página https://www.azureiotsolutions.com/, clique em + para criar uma solução.
- Clique em Selecionar no painel Monitoramento remoto para criar a solução.
- Na página Criar solução de Monitoramento remoto, insira um Nome de solução de sua escolha, selecione a Região na qual você deseja implantar e selecione a assinatura do Azure a ser usada. Clique em Criar solução.
- Aguarde até que o processo de provisionamento seja concluído.
Aviso
As soluções pré-configuradas usam serviços faturáveis do Azure. Certifique-se de remover a solução pré-configurada da sua assinatura quando tiver terminado com ela para evitar encargos desnecessários. Você pode remover completamente uma solução pré-configurada de sua assinatura acessando a página https://www.azureiotsolutions.com/.
Quando o processo de provisionamento para a solução de monitoramento remoto for concluído, clique em Iniciar para abrir o painel da solução em seu navegador.
Provisionar o dispositivo na solução de monitoramento remoto
Observação
Se você já configurou um dispositivo em sua solução, poderá ignorar esta etapa. Você precisa saber as credenciais do dispositivo ao criar o aplicativo cliente.
Para um dispositivo conectar-se à solução pré-configurada, ele deve identificar-se no Hub IoT usando credenciais válidas. Você pode recuperar as credenciais do dispositivo no painel da solução. Você pode incluir as credenciais do dispositivo em seu aplicativo cliente posteriormente neste tutorial.
Para adicionar um dispositivo à sua solução de monitoramento remoto, realize as etapas a seguir no painel da solução:
No canto inferior esquerdo do painel, clique em Adicionar um dispositivo.
No painel Dispositivo Personalizado, clique em Adicionar novo.
Escolha Deixe-me definir minha própria ID de Dispositivo. Insira uma ID do Dispositivo como mydevice, clique em Verificar ID para verificar se esse nome ainda não está em uso e, em seguida, clique em Criar para provisionar o dispositivo.
Anote as credenciais do dispositivo (ID do dispositivo, nome do host do Hub IoT e Chave do Dispositivo). Seu aplicativo cliente precisa desses valores para se conectar à solução de monitoramento remoto. Em seguida, clique em Concluído.
Selecione seu dispositivo na lista de dispositivos do painel da solução. Em seguida, no painel Detalhes do Dispositivo, clique em Habilitar Dispositivo. O status do seu dispositivo agora é Executando. Agora a solução de monitoramento remoto poderá receber telemetria do seu dispositivo e invocar métodos nele.
Criar um exemplo de solução C no Windows
As etapas a seguir mostram como criar um aplicativo cliente que se comunica com a solução pré-configurada de monitoramento remoto. Esse aplicativo é escrito em C e compilado e executado no Windows.
Crie um projeto inicial no Visual Studio 2015 ou Visual Studio 2017 e adicione os pacotes NuGet de cliente do dispositivo Hub IoT:
No Visual Studio, crie um aplicativo de console C usando o modelo Aplicativo do Console Win32 do Visual C++. Dê o nome de RMDeviceao projeto.
Na página Configurações de Aplicativos no Assistente do Aplicativo Win32, verifique se Aplicativo do Console está selecionado e desmarque Cabeçalho pré-compilado e Verificações do Security Development Lifecycle (SDL).
No Gerenciador de Soluções, exclua os arquivos stdafx.h, targetver.h e stdafx.cpp.
No Gerenciador de Soluções, renomeie o arquivo RMDevice.cpp para RMDevice.c.
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto RMDevice e clique em Gerenciar Pacotes NuGet. Clique em Procurar, para encontrar e instalar os seguintes pacotes NuGet:
- Microsoft.Azure.IoTHub.Serializer
- Microsoft.Azure.IoTHub.IoTHubClient
- Microsoft.Azure.IoTHub.MqttTransport
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto RMDevice e clique em Propriedades para abrir a caixa de diálogo Páginas de Propriedade. Para obter detalhes, confira Configurando as propriedades do projeto no Visual C++.
Clique na pasta Vinculador e clique na página de propriedade Entrada.
Adicione crypt32.lib à propriedade Dependências Adicionais. Clique em OK e OK novamente para salvar os valores da propriedade do projeto.
Adicione a biblioteca Parson JSON ao projeto RMDevice e adicione as instruções #include
necessárias:
Em uma pasta adequada no computador, clone o repositório Parson GitHub usando o seguinte comando:
git clone https://github.com/kgabis/parson.git
Copie os arquivos parson.h e parson.c da cópia local do repositório Parson para a pasta RMDevice do projeto.
No Visual Studio, clique com o botão direito do mouse no projeto RMDevice, clique em Adicionar e em Item Existente.
Na caixa de diálogo Adicionar Item Existente, selecione os arquivos parson.h e parson.c na pasta do projeto RMDevice. Em seguida, clique em Adicionar para adicionar esses dois arquivos ao projeto.
No Visual Studio, abra o arquivo RMDevice.c. Substitua as instruções
#include
existentes pelo seguinte código:#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"
Observação
Agora você pode verificar se o projeto tem as dependências corretas configuradas compilando-o.
Especificar o comportamento do dispositivo IoT
A biblioteca de cliente do serializador Hub IoT usa um modelo para especificar o formato das mensagens que o dispositivo troca com o Hub IoT.
Adicione as declarações de variável a seguir após as instruções
#include
. Substitua os valores do espaço reservado [Device ID] e [Device Key] pelos valores que você anotou para o seu dispositivo no painel da solução de monitoramento remoto. Use o nome de host do Hub IoT do painel da solução para substituir [IoTHub Name]. Por exemplo, se o nome de host do Hub IoT for contoso.azure-devices.net, substitua [Nome do HubIoT] por contoso:static const char* deviceId = "[Device Id]"; static const char* connectionString = "HostName=[IoTHub Name].azure-devices.net;DeviceId=[Device Id];SharedAccessKey=[Device Key]";
Adicione o código a seguir para definir o modelo que permite ao dispositivo se comunicar com o Hub IoT. Esse modelo especifica que o dispositivo:
- Pode enviar temperatura, temperatura externa, umidade e uma ID de dispositivo como telemetria.
- Pode enviar metadados sobre o dispositivo para o Hub IoT. O dispositivo envia metadados básicos em um objeto DeviceInfo durante a inicialização.
- Pode enviar propriedades relatadas para o dispositivo gêmeo no Hub IoT. Essas propriedades relatadas são agrupadas em propriedades de configuração, do dispositivo e do sistema.
- Pode receber e agir em propriedades desejadas definidas no dispositivo gêmeo no Hub IoT.
- Pode responder aos métodos diretos Reboot e InitiateFirmwareUpdate invocados por meio do portal da solução. O dispositivo envia informações sobre os métodos diretos aos quais ele dá suporte, usando propriedades relatadas.
// 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);
Implementar o comportamento do dispositivo
Agora adicione o código que implementa o comportamento definido no modelo.
Adicione as seguintes funções que lidam com as propriedades desejadas definidas no painel da solução. Essas propriedades desejadas são definidas no modelo:
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); }
Adicione as seguintes funções que lidam com os métodos diretos invocados por meio do Hub IoT. Esses métodos diretos são definidos no modelo:
/* 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; }
Adicione a seguinte função que envia uma mensagem para a solução pré-configurada:
/* 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); }
Adicione o seguinte manipulador de retorno de chamada que é executado quando o dispositivo envia novos valores de propriedade relatados à solução pré-configurada:
/* 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); }
Adicione a seguinte função para conectar o dispositivo à solução pré-configurada na nuvem e trocar dados. Esta função realiza as seguintes etapas:
- Inicializa a plataforma.
- Registra o namespace da Contoso na biblioteca de serialização.
- Inicializa o cliente com a cadeia de conexão do dispositivo.
- Cria uma instância do modelo Termostato.
- Cria e envia os valores de propriedade relatada.
- Envia um objeto DeviceInfo.
- Cria um loop para enviar telemetria a cada segundo.
- Realiza o desligamento de todos os recursos.
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(); }
Para referência, aqui está um exemplo de mensagem de Telemetria enviada à solução pré-configurada:
{"DeviceId":"mydevice01", "Temperature":50, "Humidity":50, "ExternalTemperature":55}
Criar e executar a amostra
Adicione código para invocar a função remote_monitoring_run e, em seguida, compile e execute o aplicativo do dispositivo.
Substitua a função main pelo seguinte código para invocar a função remote_monitoring_run:
int main() { remote_monitoring_run(); return 0; }
Clique em Compilar e em Compilar Solução para compilar o aplicativo do dispositivo.
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto RMDevice, clique em Depurar e em Iniciar nova instância para executar o exemplo. O console exibe mensagens quando o aplicativo envia a telemetria de exemplo para a solução pré-configurada, recebe os valores de propriedade desejados definidos no painel de solução e responde aos métodos invocados por meio do painel de solução.
Exibir telemetria do dispositivo no painel
O painel da solução de monitoramento remoto permite que você exiba a telemetria que seus dispositivos enviam para o Hub IoT.
Em seu navegador, retorne para o painel da solução de monitoramento remoto, clique em Dispositivos no painel esquerdo para navegar até a Lista de dispositivos.
Na Lista de dispositivos, você deve ver que o status de seu dispositivo agora é Executando. Caso contrário, clique em Habilitar Dispositivo no painel de Detalhes do Dispositivo.
Clique em Painel para voltar ao painel, selecione seu dispositivo no menu suspenso Dispositivo para Exibição para exibir sua telemetria. A telemetria do aplicativo de exemplo é de 50 unidades de temperatura interna, 55 unidades de temperatura externa e 50 unidades de umidade.
Invocar um método no seu dispositivo
O painel da solução de monitoramento remoto permite que você invoque métodos nos seus dispositivos através do Hub IoT. Por exemplo, na solução de monitoramento remoto, você pode invocar um método para simular a reinicialização de um dispositivo.
No painel da solução de monitoramento remoto, clique em Dispositivos no painel esquerdo para navegar até a Lista de dispositivos.
Clique em ID de dispositivo para seu dispositivo na Lista de dispositivos.
No painel Detalhes do dispositivo, clique em Métodos.
Na lista suspensa Método, selecione InitiateFirmwareUpdate e, em seguida, insira uma URL fictícia em FWPACKAGEURI. Clique em Invocar Método para chamar o método no dispositivo.
Você verá uma mensagem no console que está executando o código do dispositivo quando o dispositivo manipular o método. Os resultados do método serão adicionados ao histórico no portal da solução:
Próximas etapas
O artigo Personalizando soluções pré-configuradas descreve algumas maneiras de estender este exemplo. Extensões possíveis incluem usar sensores reais e implementar comandos adicionais.
Você pode aprender mais sobre as permissões no site azureiotsuite.com.