Ingesta de telemetría de IoT Hub en Azure Digital Twins

En esta guía se explica el proceso de escritura de una función que puede ingerir datos de telemetría de dispositivos desde IoT Hub y enviarlos a una instancia de Azure Digital Twins.

Azure Digital Twins se basa en los datos de los dispositivos IoT y otros orígenes. Un origen común de los datos del dispositivo que se va a usar en Azure Digital Twins es IoT Hub.

El proceso de ingesta de datos en Azure Digital Twins consiste en configurar un recurso de proceso externo como, por ejemplo, una función creada con Azure Functions. La función recibe los datos y usa las API de DigitalTwins para establecer propiedades o desencadenar eventos de telemetría en los gemelos digitales en consecuencia.

Este documento de procedimientos le guía por el proceso para escribir una función que puede ingerir telemetría del dispositivo desde IoT Hub.

Requisitos previos

Antes de continuar con este ejemplo, debe configurar los siguientes recursos como requisito previo:

Escenario de telemetría de ejemplo

En este procedimiento se explica cómo enviar mensajes desde IoT Hub a Azure Digital Twins, mediante una función de Azure. Hay muchas configuraciones y estrategias de coincidencia posibles que puede usar para enviar mensajes, pero el ejemplo de este artículo contiene los siguientes elementos:

  • Un dispositivo de termómetro en IoT Hub, con un identificador de dispositivo conocido
  • Un gemelo digital para representar el dispositivo, con un identificador coincidente

Nota:

En este ejemplo se usa una coincidencia de identificador sencillo entre el identificador de dispositivo y el identificador de gemelo digital correspondiente, pero es posible proporcionar asignaciones más sofisticadas del dispositivo a su gemelo (por ejemplo, con una tabla de asignación).

Cada vez que el dispositivo de termostato envía un evento de telemetría de temperatura, una función procesa la telemetría y la Temperature propiedad del gemelo digital debe actualizarse. Este escenario se describe en un diagrama a continuación:

Diagram of IoT Hub device sending Temperature telemetry to a function in Azure, which updates a Temperature property on a twin in Azure Digital Twins.

Adición de un modelo y un gemelo

En esta sección, configurará un gemelo digital en Azure Digital Twins que representará el dispositivo de termostato, y se actualizará con información de IoT Hub.

Para crear un gemelo de tipo termostato, primero debe cargar el modelo de termostato en la instancia, que describe las propiedades de un termostato y que se usará más adelante para crear el gemelo.

El modelo tiene este aspecto:

{
    "@id": "dtmi:contosocom:DigitalTwins:Thermostat;1",
    "@type": "Interface",
    "@context": "dtmi:dtdl:context;3",
    "contents": [
      {
        "@type": "Property",
        "name": "Temperature",
        "schema": "double"
      }
    ]
  }

Para cargar este modelo en la instancia del gemelo, ejecute el siguiente comando de la CLI de Azure, que carga el modelo anterior como JSON insertado. Puede ejecutar el comando en Azure Cloud Shell en el explorador (use el entorno de Bash) o en el equipo si tiene la CLI instalada localmente. Hay un marcador de posición para el nombre de host de la instancia (también puede usar el nombre descriptivo de la instancia con una ligera disminución del rendimiento).

az dt model create --dt-name <instance-hostname-or-name> --models '{  "@id": "dtmi:contosocom:DigitalTwins:Thermostat;1",  "@type": "Interface",  "@context": "dtmi:dtdl:context;2",  "contents": [    {      "@type": "Property",      "name": "Temperature",      "schema": "double"    }  ]}' 

Nota:

Si usa un servicio que no sea Cloud Shell en el entorno de Bash, es posible que tenga que escapar determinados caracteres en el JSON insertado para que se analice correctamente. Para obtener más información, consulte Uso de caracteres especiales en distintos shells.

A continuación, deberá crear un gemelo con este modelo. Use el comando siguiente para crear un gemelo de termostato llamado thermostat67 y establezca 0,0 como valor de temperatura inicial. Hay un marcador de posición para el nombre de host de la instancia (también puede usar el nombre descriptivo de la instancia con una ligera disminución del rendimiento).

az dt twin create  --dt-name <instance-hostname-or-name> --dtmi "dtmi:contosocom:DigitalTwins:Thermostat;1" --twin-id thermostat67 --properties '{"Temperature": 0.0}'

Si el gemelo se crea correctamente, la salida de la CLI del comando debe ser similar a la siguiente:

{
  "$dtId": "thermostat67",
  "$etag": "W/\"0000000-9735-4f41-98d5-90d68e673e15\"",
  "$metadata": {
    "$model": "dtmi:contosocom:DigitalTwins:Thermostat;1",
    "Temperature": {
      "lastUpdateTime": "2021-09-09T20:32:46.6692326Z"
    }
  },
  "Temperature": 0.0
}

Creación de la función de Azure

En esta sección, creará una función de Azure para acceder a Azure Digital Twins y actualizará gemelos en función de los eventos de telemetría de dispositivos IoT que recibe. Siga los pasos que se indican a continuación para crear y publicar la función.

  1. En primer lugar, cree un nuevo proyecto de Azure Functions del tipo de desencadenador de Event Grid.

    Para ello, puede usar Visual Studio (para más instrucciones, consulte Desarrollo de Azure Functions con Visual Studio), Visual Studio Code (para más instrucciones, consulte Creación de una función de C# en Azure mediante Visual Studio Code ) o la CLI de Azure (para más instrucciones, consulte Creación de una función de C# en Azure desde la línea de comandos).

  2. Agregue los siguientes paquetes al proyecto (para ello, puede usar el administrador de paquetes NuGet de Visual Studio o el comando dotnet add package en una herramienta de línea de comandos).

  3. Cree una función en el proyecto denominado IoTHubtoTwins.cs. Pegue el código siguiente en el archivo de función:

    using System;
    using Azure;
    using System.Net.Http;
    using Azure.Core.Pipeline;
    using Azure.DigitalTwins.Core;
    using Azure.Identity;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.EventGrid;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using Azure.Messaging.EventGrid;
    
    namespace IotHubtoTwins
    {
        public class IoTHubtoTwins
        {
            private static readonly string adtInstanceUrl = Environment.GetEnvironmentVariable("ADT_SERVICE_URL");
            private static readonly HttpClient httpClient = new HttpClient();
    
            [FunctionName("IoTHubtoTwins")]
            // While async void should generally be used with caution, it's not uncommon for Azure function apps, since the function app isn't awaiting the task.
    #pragma warning disable AZF0001 // Suppress async void error
            public async void Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
    #pragma warning restore AZF0001 // Suppress async void error
            {
                if (adtInstanceUrl == null) log.LogError("Application setting \"ADT_SERVICE_URL\" not set");
    
                try
                {
                    // Authenticate with Digital Twins
                    var cred = new DefaultAzureCredential();
                    var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred);
                    log.LogInformation($"ADT service client connection created.");
                
                    if (eventGridEvent != null && eventGridEvent.Data != null)
                    {
                        log.LogInformation(eventGridEvent.Data.ToString());
    
                        // <Find_device_ID_and_temperature>
                        JObject deviceMessage = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());
                        string deviceId = (string)deviceMessage["systemProperties"]["iothub-connection-device-id"];
                        var temperature = deviceMessage["body"]["Temperature"];
                        // </Find_device_ID_and_temperature>
    
                        log.LogInformation($"Device:{deviceId} Temperature is:{temperature}");
    
                        // <Update_twin_with_device_temperature>
                        var updateTwinData = new JsonPatchDocument();
                        updateTwinData.AppendReplace("/Temperature", temperature.Value<double>());
                        await client.UpdateDigitalTwinAsync(deviceId, updateTwinData);
                        // </Update_twin_with_device_temperature>
                    }
                }
                catch (Exception ex)
                {
                    log.LogError($"Error in ingest function: {ex.Message}");
                }
            }
        }
    }
    

    Guarde el código de función.

  4. Publique el proyecto con la función IoTHubtoTwins.cs en una aplicación de funciones de Azure.

    Para más instrucciones sobre cómo publicar la función mediante Visual Studio, consulte Desarrollo de Azure Functions con Visual Studio. Para más instrucciones sobre cómo publicar la función mediante Visual Studio Code, consulte Creación de una función de C# en Azure mediante Visual Studio Code. Para obtener instrucciones sobre cómo publicar la función mediante la CLI de Azure, consulte Creación de una función de C# en Azure desde la línea de comandos.

Una vez completado el proceso de publicación de la función, puede usar el comando de la CLI de Azure para comprobar que la publicación se haya realizado correctamente. Hay marcadores de posición para el grupo de recursos y el nombre de la aplicación de funciones. El comando imprimirá la información sobre la función IoTHubToTwins.

az functionapp function show --resource-group <your-resource-group> --name <your-function-app> --function-name IoTHubToTwins

Configuración de la Function App

Para acceder a Azure Digital Twins, la aplicación de funciones necesita una identidad administrada asignada por el sistema con permisos para acceder a la instancia de Azure Digital Twins. Deberá configurar esto en esta sección mediante la asignación de un rol de acceso para la función y la configuración de los valores de la aplicación para que pueda acceder a la instancia de Azure Digital Twins.

Ejecute los comandos siguientes en Azure Cloud Shell o en una interfaz de la línea de comandos (CLI) local de Azure.

Nota:

Esta sección la debe completar un usuario de Azure que tenga permisos para administrar el acceso de los usuarios a los recursos de Azure, lo cual abarca la concesión y delegación de permisos. Los roles comunes que cumplen este requisito son propietario, administrador de cuentas o la combinación de administrador de acceso de usuarios y colaborador. Para obtener más información sobre los requisitos de permisos para los roles de Azure Digital Twins, vea Configuración de una instancia y autenticación.

Asignación de un rol de acceso

La función de Azure requiere que se le pase un token de portador. Para asegurarse de que el token de portador se haya pasado, conceda a la aplicación de funciones el rol de propietario de datos de Azure Digital Twins para la instancia de Azure Digital Twins, lo que dará permiso a la aplicación de funciones para realizar actividades del plano de datos en la instancia.

  1. Use el comando siguiente a fin de crear una identidad administrada por el sistema para la función (si la función ya tiene una, este comando imprimirá sus detalles). Tome nota del principalId campo en la salida. Este identificador se usará para hacer referencia a la función de forma que pueda concederle permisos en el paso siguiente.

    az functionapp identity assign --resource-group <your-resource-group> --name <your-function-app-name>	
    
  2. Use el valor principalId en el comando siguiente para asignar a la función el rol de propietario de datos de Azure Digital Twins en la instancia de Azure Digital Twins.

    az dt role-assignment create --dt-name <your-Azure-Digital-Twins-instance> --assignee "<principal-ID>" --role "Azure Digital Twins Data Owner"
    

Configuración de la aplicación

A continuación, establezca una variable de entorno para que la dirección URL de la instancia de Azure Digital Twins sea accesible para la función.

Sugerencia

Para crear la dirección URL de la instancia de Azure Digital Twins, agregue https:// al principio del nombre de host de la instancia. Para ver el nombre de host, junto con todas las propiedades de la instancia, ejecute az dt show --dt-name <your-Azure-Digital-Twins-instance>.

El comando siguiente establece una variable de entorno para la dirección URL de la instancia que la función usará siempre que necesite acceder a la instancia.

az functionapp config appsettings set --resource-group <your-resource-group> --name <your-function-app-name> --settings "ADT_SERVICE_URL=https://<your-Azure-Digital-Twins-instance-host-name>"

Conexión de la función a IoT Hub

En esta sección, configurará la función como un destino de evento para los datos del dispositivo de IoT Hub. Si configura la función de esta forma, se asegurará de que los datos del dispositivo de termostato de IoT Hub se enviarán a la función de Azure para procesarlos.

Use el siguiente comando de la CLI para crear una suscripción de eventos que IoT Hub usará para enviar datos de eventos a la función IoTHubtoTwins. Hay un marcador de posición para que escriba un nombre para la suscripción de eventos y también hay marcadores de posición para que escriba el identificador de suscripción, el grupo de recursos, el nombre del centro de IoT y el nombre de la aplicación de funciones.

az eventgrid event-subscription create --name <name-for-hub-event-subscription> --event-delivery-schema eventgridschema --source-resource-id /subscriptions/<your-subscription-ID>/resourceGroups/<your-resource-group>/providers/Microsoft.Devices/IotHubs/<your-IoT-hub> --included-event-types Microsoft.Devices.DeviceTelemetry --endpoint-type azurefunction --endpoint /subscriptions/<your-subscription-ID>/resourceGroups/<your-resource-group>/providers/Microsoft.Web/sites/<your-function-app>/functions/IoTHubtoTwins

La salida mostrará información sobre la suscripción de eventos que se ha creado. Puede confirmar que la operación se ha completado correctamente mediante la comprobación del valor provisioningState en el resultado:

"provisioningState": "Succeeded",

Prueba con datos de IoT simulados

Puede probar la nueva función de entrada mediante el uso del simulador de dispositivos de Conexión de una solución de un extremo a otro. El proyecto DeviceSimulator contiene un dispositivo termostato simulado que envía datos de temperatura de muestra. Para configurar el simulador de dispositivos, siga estos pasos:

  1. Vaya al repositorio de proyectos de muestra de un extremo a otro de Azure Digital Twins. Para tener el proyecto de muestra en su máquina, seleccione el botón Examinar código situado debajo del título. Esto le llevará al repositorio de GitHub de los ejemplos, que se pueden descargar como un archivo .zip si se selecciona el botón Código y después Descargar archivo ZIP.

    Esta acción descargará una carpeta .zip en la máquina denominada digital-twins-samples-main.zip. Descomprima la carpeta y extraiga los archivos. Usará la carpeta del proyecto DeviceSimulator.

  2. Registro del dispositivo simulado con IoT Hub

  3. Configuración y ejecución de la simulación

Después de completar estos pasos, debe tener una ventana de consola del proyecto en ejecución y enviar datos de telemetría de dispositivos simulados a IoT Hub.

Screenshot of the output from the device simulator project.

Validación de los resultados

Mientras se ejecuta el simulador de dispositivos anterior, cambiará el valor de temperatura del gemelo digital del termostato. En la CLI de Azure, ejecute el siguiente comando para ver el valor de temperatura. Hay un marcador de posición para el nombre de host de la instancia (también puede usar el nombre descriptivo de la instancia con una ligera disminución del rendimiento).

az dt twin query --query-command "SELECT * FROM digitaltwins WHERE \$dtId = 'thermostat67'" --dt-name <instance-hostname-or-name>

Nota:

Si usa un servicio que no sea Cloud Shell en el entorno de Bash, es posible que tenga que escapar el carácter $ en la consulta de manera diferente para que se analice correctamente. Para obtener más información, consulte Uso de caracteres especiales en distintos shells.

El resultado debe mostrar los detalles del gemelo thermostat67, incluido un valor de temperatura, como este:

{
  "result": [
    {
      "$dtId": "thermostat67",
      "$etag": "W/\"dbf2fea8-d3f7-42d0-8037-83730dc2afc5\"",
      "$metadata": {
        "$model": "dtmi:contosocom:DigitalTwins:Thermostat;1",
        "Temperature": {
          "lastUpdateTime": "2021-06-03T17:05:52.0062638Z"
        }
      },
      "Temperature": 70.20518558807913
    }
  ]
}

Para ver el cambio de valor Temperature, ejecute repetidamente el comando de consulta anterior.

Pasos siguientes

Obtenga información sobre la entrada y salida de datos con Azure Digital Twins: