Conectar el dispositivo a la solución preconfigurada de supervisión remota (Linux)
Información general de escenario
En este escenario, creará un dispositivo que envía la siguiente telemetría a la solución preconfigurada de supervisión remota:
- Temperatura exterior
- Temperatura interior
- Humedad
Para simplificar, el código del dispositivo genera valores de ejemplo, pero le recomendamos que amplíe el ejemplo conectando sensores reales a su dispositivo y enviando telemetría real.
El dispositivo también puede responder a los métodos que se invocan desde el panel de la solución y los valores de propiedades deseadas establecidos en el panel de la solución.
Para completar este tutorial, deberá tener una cuenta activa de Azure. En caso de no tener cuenta, puede crear una de evaluación gratuita en tan solo unos minutos. Para obtener más información, consulte Evaluación gratuita de Azure.
Antes de comenzar
Antes de escribir ningún código para el dispositivo, debe aprovisionar la solución preconfigurada de supervisión remota y aprovisionar un nuevo dispositivo personalizado en esa solución.
Aprovisionar su solución preconfigurada de supervisión remota
El dispositivo que cree en este tutorial enviará datos a una instancia de la solución preconfigurada de supervisión remota. Si todavía no aprovisionó la solución preconfigurada de supervisión remota en su cuenta de Azure, use estos pasos:
- En la página https://www.azureiotsolutions.com/, haga clic en + para crear una solución.
- Haga clic en Seleccionar en el panel de supervisión remota para crear la solución.
- En la página Create Remote monitoring solution (Crear solución de supervisión remota), escriba el nombre de solución que prefiera, seleccione la región en la que desea realizar la implementación y seleccione la suscripción de Azure que desea usar. Haga clic en Crear solución.
- Espere a que finalice el proceso de aprovisionamiento.
Advertencia
Las soluciones preconfiguradas utilizan servicios de Azure facturables. Para evitar gastos innecesarios, asegúrese de quitar la solución preconfigurada de la suscripción cuando haya terminado. Para quitar completamente una solución preconfigurada de su suscripción, diríjase a la página https://www.azureiotsolutions.com/.
Cuando finalice el proceso de aprovisionamiento para la solución de supervisión remota, haga clic en Iniciar para abrir el panel de la solución en el explorador.
Aprovisionar el dispositivo en la solución de supervisión remota
Nota
Si ya ha aprovisionado un dispositivo en la solución, puede omitir este paso. Debe conocer las credenciales del dispositivo cuando cree la aplicación cliente.
Para que un dispositivo se conecte a la solución preconfigurada, debe identificarse en Azure IoT Hub con credenciales válidas. Puede recuperar las credenciales del dispositivo desde el panel de la solución. Incluirá las credenciales del dispositivo en la aplicación de cliente más adelante en este tutorial.
Para agregar un dispositivo a su solución de supervisión remota, complete los pasos siguientes en el panel de la solución:
En la esquina inferior izquierda del panel, haga clic en Agregar un dispositivo.
En el panel Dispositivo personalizado, haga clic en Agregar nuevo.
Elija Permitirme definir mi propio id. de dispositivo. Especifique un id. de dispositivo, como mydevice, haga clic en Comprobar id. para comprobar que el nombre todavía no está en uso y, luego, haga clic en Crear para aprovisionar el dispositivo.
Anote las credenciales de dispositivo (id. de dispositivo, nombre de host de IoT Hub y clave de dispositivo). La aplicación cliente necesita estos valores para conectarse con la solución de supervisión remota. A continuación, haga clic en Hecho.
Seleccione el dispositivo en la lista de dispositivos del panel de la solución. Luego, en el panel Detalles del dispositivo, haga clic en Habilitar dispositivo. El estado del dispositivo ahora es En ejecución. La solución de supervisión remota ahora puede recibir telemetría desde el dispositivo e invocar métodos en el dispositivo.
Compilación y ejecución de una aplicación cliente de C de ejemplo (Linux)
En los siguientes pasos se explica cómo crear una aplicación cliente que se comunique con la solución preconfigurada de supervisión remota. Esta aplicación se escribe en C y se compila y ejecuta en Ubuntu Linux.
Para completar estos pasos, necesita un dispositivo que ejecute la versión 15.04 o 15.10 de Ubuntu. Antes de continuar, instale los paquetes de requisitos previos en el dispositivo Ubuntu ejecutando el siguiente comando:
sudo apt-get install cmake gcc g++
Instalación de las bibliotecas de cliente en el dispositivo
Las bibliotecas de cliente de Azure IoT Hub están disponibles como un paquete que puede instalar en su dispositivo Ubuntu ejecutando el comando apt-get . Complete los pasos siguientes para instalar el paquete que contiene la biblioteca de cliente de IoT Hub y los archivos de encabezado de su equipo Ubuntu:
En un shell, agregue el repositorio de AzureIoT al equipo:
sudo add-apt-repository ppa:aziotsdklinux/ppa-azureiot sudo apt-get update
Instale el paquete azure-iot-sdk-c-dev:
sudo apt-get install -y azure-iot-sdk-c-dev
Instalación del analizador JSON de Parson
Las bibliotecas de cliente de IoT Hub emplean el analizador JSON de Parson para analizar cargas de mensajes. En una carpeta adecuada del equipo, clone el repositorio GitHub de Parson mediante el siguiente comando:
git clone https://github.com/kgabis/parson.git
Preparación del proyecto
En la máquina Ubuntu, cree una carpeta denominada remote_monitoring. En la carpeta remote_monitoring :
- Cree los cuatro archivos main.c, remote_monitoring.c, remote_monitoring.h y CMakeLists.txt.
- Cree la carpeta denominada parson.
Copie los archivos parson.c y parson.h de la copia local del repositorio de Parson en la carpeta remote_monitoring/parson .
En un editor de texto, abra el archivo remote_monitoring.c. Agregue las instrucciones siguientes #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"
Especificación del comportamiento del dispositivo IoT
La biblioteca de cliente del serializador de IoT Hub usa un modelo para especificar el formato de los mensajes que el dispositivo intercambia con IoT Hub.
Agregue las siguientes declaraciones de variable después de las instrucciones
#include
. Sustituya los valores de marcador de posición [Device Id] y [Device Key] por los valores que anotó para el dispositivo en el panel de la solución de supervisión remota. Use el nombre de host de IoT Hub en el panel de la solución para sustituir [IoTHub Name]. Por ejemplo, si el nombre de host de IoT Hub es contoso.azure-devices.net, sustituya [IoTHub Name] por contoso:static const char* deviceId = "[Device Id]"; static const char* connectionString = "HostName=[IoTHub Name].azure-devices.net;DeviceId=[Device Id];SharedAccessKey=[Device Key]";
Agregue el código siguiente para definir el modelo que permite que el dispositivo se comunique con IoT Hub. Este modelo especifica que el dispositivo:
- Puede enviar datos de temperatura, temperatura externa, humedad y un identificador de dispositivo como telemetría.
- Puede enviar datos sobre el dispositivo a IoT Hub. El dispositivo envía metadatos básicos en un objeto DeviceInfo en el inicio.
- Puede enviar propiedades notificadas al dispositivo gemelo en IoT Hub. Estas propiedades notificadas se agrupan en propiedades de configuración, dispositivo y sistema.
- Puede recibir las propiedades deseadas establecidas en el dispositivo gemelo en IoT Hub y actuar en función de ellas.
- Puede responder a los métodos directos Reboot y InitiateFirmwareUpdate mediante el portal de la solución. El dispositivo envía información sobre los métodos directos que admite mediante las propiedades notificadas.
// 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);
Implementación del comportamiento del dispositivo
Ahora, agregue código que implemente el comportamiento definido en el modelo.
Agregue las siguientes funciones que controlan las propiedades deseadas establecidas en el panel de la solución. Estas propiedades deseadas se definen en el 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); }
Agregue las funciones siguientes que controlan los métodos directos que se invocan a través de IoT Hub. Estos métodos directos se definen en el 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; }
Agregue la función siguiente que envía un mensaje a la solución preconfigurada:
/* 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); }
Agregue el siguiente controlador de devolución de llamadas que se ejecuta cuando el dispositivo ha enviado nuevos valores de propiedades notificadas a la solución preconfigurada:
/* 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); }
Agregue la función siguiente para conectar el dispositivo a la solución preconfiguradas en la nube e intercambiar datos. Esta función lleva a cabo los pasos siguientes:
- Inicializa la plataforma.
- Registra el espacio de nombres Contoso con la biblioteca de serialización.
- Inicializa el cliente con la cadena de conexión del dispositivo.
- Crea una instancia del modelo del termostato.
- Crea y envía valores de propiedades notificadas.
- Envía un objeto DeviceInfo.
- Crea un bucle para enviar telemetría a cada segundo.
- Desinicializa todos los 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(); }
Como referencia, este es un mensaje de telemetría de ejemplo enviado a la solución preconfigurado:
{"DeviceId":"mydevice01", "Temperature":50, "Humidity":50, "ExternalTemperature":55}
Llamada a la función remote_monitoring_run
En un editor de texto, abra el archivo remote_monitoring.h. Agregue el siguiente código:
void remote_monitoring_run(void);
En un editor de texto, abra el archivo main.c . Agregue el siguiente código:
#include "remote_monitoring.h"
int main(void)
{
remote_monitoring_run();
return 0;
}
Compilación y ejecución de la aplicación
En los pasos siguientes se describe cómo puede utilizar CMake para compilar la aplicación cliente.
En un editor de texto, abra el archivo CMakeLists.txt de la carpeta remote_monitoring.
Agregue las siguientes instrucciones para definir cómo compilar la aplicación cliente:
macro(compileAsC99) if (CMAKE_VERSION VERSION_LESS "3.1") if (CMAKE_C_COMPILER_ID STREQUAL "GNU") set (CMAKE_C_FLAGS "--std=c99 ${CMAKE_C_FLAGS}") set (CMAKE_CXX_FLAGS "--std=c++11 ${CMAKE_CXX_FLAGS}") endif() else() set (CMAKE_C_STANDARD 99) set (CMAKE_CXX_STANDARD 11) endif() endmacro(compileAsC99) cmake_minimum_required(VERSION 2.8.11) compileAsC99() set(AZUREIOT_INC_FOLDER "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/parson" "/usr/include/azureiot" "/usr/include/azureiot/inc") include_directories(${AZUREIOT_INC_FOLDER}) set(sample_application_c_files ./parson/parson.c ./remote_monitoring.c ./main.c ) set(sample_application_h_files ./parson/parson.h ./remote_monitoring.h ) add_executable(sample_app ${sample_application_c_files} ${sample_application_h_files}) target_link_libraries(sample_app serializer iothub_client iothub_client_mqtt_transport aziotsharedutil umqtt pthread curl ssl crypto m )
En la carpeta remote_monitoring, cree otra para almacenar los archivos make que genera CMake y, después, ejecute los comandos cmake y make, tal y como se muestra a continuación:
mkdir cmake cd cmake cmake ../ make
Ejecute la aplicación cliente y envíe los datos telemetría a IoT Hub:
./sample_app
Ver la telemetría de dispositivo en el panel
El panel de la solución de supervisión remota permite ver la telemetría que los dispositivos envían a IoT Hub.
En el explorador, vuelva al panel de la solución de supervisión remota, haga clic en Dispositivos en el panel izquierdo para navegar hasta la lista de dispositivos.
En la lista de dispositivos, debería ver que el estado del dispositivo es En ejecución. Si no es así, haga clic en Habilitar dispositivo en el panel Detalles del dispositivo.
Haga clic en el Panel para volver a él, seleccione el dispositivo en la lista desplegable Device to View (Dispositivo para ver) para ver su telemetría. La telemetría de la aplicación de ejemplo es 50 unidades para la temperatura interior, 55 unidades para la temperatura exterior y 50 unidades para la humedad.
Invocar un método en el dispositivo
El panel de la solución de supervisión remota le permite invocar métodos en los dispositivos a través de IoT Hub. Por ejemplo, en la solución de supervisión remota, puede invocar un método para simular que se reinicia un dispositivo.
En el panel de la solución de supervisión remota, haga clic en Devices (Dispositivos) en el panel izquierdo para navegar a la lista de dispositivos.
Haga clic en Device ID (Id. de dispositivo) en el dispositivo de la lista de dispositivos.
En el panel Detalles del dispositivo, haga clic en Métodos.
En el menú desplegable Método, seleccione InitiateFirmwareUpdate y, luego, en FWPACKAGEURI, escriba una dirección URL ficticia. Haga clic en Invocar método para llamar al método en el dispositivo.
Puede ver un mensaje en la consola donde se ejecuta el código del dispositivo cuando el dispositivo controla el método. Los resultados del método se agregan al historial en el portal de la solución:
Pasos siguientes
En el artículo Personalización de soluciones preconfiguradas se describen algunas formas de ampliar este ejemplo. Entre las posibles extensiones se incluyen el uso de sensores reales y la implementación de comandos adicionales.
Puede obtener más información sobre los permisos en el sitio azureiotsuite.com.