Compartir a través de


Administración automática de dispositivos en Azure Digital Twins mediante Device Provisioning Service (DPS)

En este artículo, aprenderá a integrar Azure Digital Twins con Device Provisioning Service (DPS).

La solución que se describe en este artículo le permitirá automatizar el proceso de aprovisionar y retirar dispositivos IoT Hub de Azure Digital Twins mediante Device Provisioning Service.

Para más información sobre las fases de aprovisionamiento y retirada, y para comprender mejor el conjunto de fases generales de administración de dispositivos que son comunes a todos los proyectos de IoT empresarial, consulte la sección Ciclo de vida del dispositivo de la documentación de administración de dispositivos de IoT Hub.

Requisitos previos

Antes de configurar el aprovisionamiento, debe configurar los recursos siguientes:

En este ejemplo también se usa un simulador de dispositivos que incluye el aprovisionamiento mediante Device Provisioning Service. El simulador de dispositivos se encuentra aquí: Ejemplo de integración de Azure Digital Twins e IoT Hub. Para obtener el proyecto de ejemplo en la máquina, vaya al repositorio de GitHub del ejemplo, que puede descargar como un archivo .zip seleccionando el botón Código y Descargar archivo ZIP.

Captura de pantalla del repositorio digital-twins-iothub-integration en GitHub, donde están resaltados los pasos necesarios para descargarlo en forma de archivo ZIP.

Descomprima la carpeta descargada.

Asegúrese de tener Node.js instalado en la máquina. El simulador de dispositivos se basa en Node.js, versión 10.0.x u otra posterior.

Arquitectura de la solución

Esta solución incluye los pasos necesarios para aprovisionar y retirar un dispositivo en Azure Digital Twins mediante Device Provisioning Service.

Para asignar dispositivos en la solución, fluyen datos entre un dispositivo termostato y DPS. Luego, los datos fluyen entre DPS e IoT Hub y Azure Digital Twins a través de una función de Azure.

Para retirar un dispositivo, los datos de eliminación manual del dispositivos fluyen a Azure Digital Twins a través de IoT Hub, Event Hubs y una función de Azure.

En la imagen siguiente se ilustra esta arquitectura.

Diagrama de un dispositivo y varios servicios de Azure en un escenario de extremo a extremo que muestra el flujo de datos.

Este artículo se divide en dos secciones, y cada una de ellas se centra en una parte de esta arquitectura completa:

Aprovisionamiento automático de un dispositivo mediante Device Provisioning Service

En esta sección, va a conectar Device Provisioning Service a Azure Digital Twins para aprovisionar automáticamente los dispositivos a través de la ruta de acceso siguiente. Este diagrama es un extracto de la arquitectura completa que se ha mostrado anteriormente.

Diagrama de flujo de aprovisionamiento: un extracto del diagrama de la arquitectura de la solución que sigue los datos de un termostato en Azure Digital Twins.

Esta es una descripción del flujo del proceso:

  1. El dispositivo se pone en contacto con el punto de conexión de DPS y pasa la información de identificación para demostrar su identidad.
  2. DPS valida la identidad del dispositivo mediante la validación del identificador y la clave de registro en comparación con la lista de inscripción y llama a una función de Azure para realizar la asignación.
  3. La función de Azure crea un nuevo gemelo en Azure Digital Twins para el dispositivo. El gemelo tendrá el mismo nombre que el identificador de registrodel dispositivo.
  4. DPS registra el dispositivo con un centro de IoT y rellena el estado deseado de los dispositivos gemelos.
  5. El centro de IoT devuelve la información sobre la identidad del dispositivo y la conexión del centro de IoT al dispositivo. Ahora el dispositivo puede conectarse al centro de IoT.

En las siguientes secciones se describen los pasos necesarios para configurar este flujo de aprovisionamiento automático del dispositivo.

Creación de una instancia de Device Provisioning Service

Cuando se aprovisiona un nuevo dispositivo mediante el servicio de aprovisionamiento de dispositivos, se puede crear un nuevo dispositivo gemelo para ese dispositivo en Azure Digital Twins con el mismo nombre como id. de registro.

Cree una instancia de Device Provisioning Service que se usará para aprovisionar dispositivos IoT. Puede usar las instrucciones de la CLI de Azure que aparecen a continuación o usar Azure Portal siguiendo las instrucciones de Inicio rápido: Configuración de Azure IoT Hub Device Provisioning Service con Azure Portal.

El siguiente comando de la CLI de Azure creará una instancia de Device Provisioning Service. Deberá especificar un nombre de servicio de aprovisionamiento de dispositivos, un grupo de recursos y una región. Para ver qué regiones admiten el Servicio de aprovisionamiento de dispositivos, visite Productos de Azure disponibles por región. El comando se puede ejecutar en Cloud Shell, o bien localmente si tiene la CLI de Azure está instalada en la máquina.

az iot dps create --name <Device-Provisioning-Service-name> --resource-group <resource-group-name> --location <region>

Incorporación de una función que se va a usar con el servicio aprovisionamiento de dispositivos

En el proyecto de la aplicación de funciones que creó en la sección de requisitos previos creará una función que se usará con Device Provisioning Service. Device Provisioning Service usará esta función en una directiva de asignación personalizada para aprovisionar un nuevo dispositivo.

Vaya al proyecto de aplicación de función ubicado en la máquina y siga los pasos que se describen a continuación.

  1. Primero, cree una función de tipo HTTP-trigger en el proyecto de aplicación de función.

  2. Agregue un nuevo paquete de NuGet al proyecto: Microsoft.Azure.Devices.Provisioning.Service. Es posible que también tenga que agregar más paquetes al proyecto si los paquetes usados en el código ya no forman parte del proyecto.

  3. En el archivo de código de la función recién creada, pegue el código siguiente, denomínela con el nombre DpsAdtAllocationFunc.cs y guarde el archivo.

    // Copyright (c) Microsoft. All rights reserved.
    // Licensed under the MIT license. See LICENSE file in the project root for full license information.
    
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Http;
    using System.Threading.Tasks;
    using Azure;
    using Azure.Core.Pipeline;
    using Azure.DigitalTwins.Core;
    using Azure.Identity;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.Http;
    using Microsoft.Azure.Devices.Shared;
    using Microsoft.Azure.Devices.Provisioning.Service;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    
    namespace Samples.AdtIothub
    {
        public static class DpsAdtAllocationFunc
        {
            private static string adtInstanceUrl = Environment.GetEnvironmentVariable("ADT_SERVICE_URL");
            private static readonly HttpClient singletonHttpClientInstance = new HttpClient();
    
            [FunctionName("DpsAdtAllocationFunc")]
            public static async Task<IActionResult> Run(
                [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
            {
                // Get request body
                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                log.LogDebug($"Request.Body: {requestBody}");
                dynamic data = JsonConvert.DeserializeObject(requestBody);
    
                // Get registration ID of the device
                string regId = data?.deviceRuntimeContext?.registrationId;
    
                bool fail = false;
                string message = "Uncaught error";
                var response = new ResponseObj();
    
                // Must have unique registration ID on DPS request
                if (regId == null)
                {
                    message = "Registration ID not provided for the device.";
                    log.LogInformation("Registration ID: NULL");
                    fail = true;
                }
                else
                {
                    string[] hubs = data?.linkedHubs.ToObject<string[]>();
    
                    // Must have hubs selected on the enrollment
                    if (hubs == null
                        || hubs.Length < 1)
                    {
                        message = "No hub group defined for the enrollment.";
                        log.LogInformation("linkedHubs: NULL");
                        fail = true;
                    }
                    else
                    {
                        // Find or create twin based on the provided registration ID and model ID
                        dynamic payloadContext = data?.deviceRuntimeContext?.payload;
                        string dtmi = payloadContext.modelId;
                        log.LogDebug($"payload.modelId: {dtmi}");
                        string dtId = await FindOrCreateTwinAsync(dtmi, regId, log);
    
                        // Get first linked hub (TODO: select one of the linked hubs based on policy)
                        response.iotHubHostName = hubs[0];
    
                        // Specify the initial tags for the device.
                        var tags = new TwinCollection();
                        tags["dtmi"] = dtmi;
                        tags["dtId"] = dtId;
    
                        // Specify the initial desired properties for the device.
                        var properties = new TwinCollection();
    
                        // Add the initial twin state to the response.
                        var twinState = new TwinState(tags, properties);
                        response.initialTwin = twinState;
                    }
                }
    
                log.LogDebug("Response: " + ((response.iotHubHostName != null)? JsonConvert.SerializeObject(response) : message));
    
                return fail
                    ? new BadRequestObjectResult(message)
                    : (ActionResult)new OkObjectResult(response);
            }
    
            public static async Task<string> FindOrCreateTwinAsync(string dtmi, string regId, ILogger log)
            {
                // Create Digital Twins client
                var cred = new DefaultAzureCredential();
                var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred);
    
                // Find existing DigitalTwin with registration ID
                try
                {
                    // Get DigitalTwin with Id 'regId'
                    BasicDigitalTwin existingDt = await client.GetDigitalTwinAsync<BasicDigitalTwin>(regId).ConfigureAwait(false);
    
                    // Check to make sure it is of the correct model type
                    if (StringComparer.OrdinalIgnoreCase.Equals(dtmi, existingDt.Metadata.ModelId))
                    {
                        log.LogInformation($"DigitalTwin {existingDt.Id} already exists");
                        return existingDt.Id;
                    }
    
                    // Found DigitalTwin but it is not of the correct model type
                    log.LogInformation($"Found DigitalTwin {existingDt.Id} but it is not of model {dtmi}");
                }
                catch(RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.NotFound)
                {
                    log.LogDebug($"Did not find DigitalTwin {regId}");
                }
    
                // Either the DigitalTwin was not found, or we found it but it is of a different model type
                // Create or replace it with what it needs to be, meaning if it was not found a brand new DigitalTwin will be created
                // and if it was of a different model, it will replace that existing DigitalTwin
                // If it was intended to only create the DigitalTwin if there is no matching DigitalTwin with the same Id,
                // ETag.All could have been used as the ifNonMatch parameter to the CreateOrReplaceDigitalTwinAsync method call.
                // Read more in the CreateOrReplaceDigitalTwinAsync documentation here:
                // https://docs.microsoft.com/en-us/dotnet/api/azure.digitaltwins.core.digitaltwinsclient.createorreplacedigitaltwinasync?view=azure-dotnet
                BasicDigitalTwin dt = await client.CreateOrReplaceDigitalTwinAsync(
                    regId, 
                    new BasicDigitalTwin
                    {
                        Metadata = { ModelId = dtmi },
                        Contents = 
                        {
                            { "Temperature", 0.0 }
                        }
                    }
                ).ConfigureAwait(false);
    
                log.LogInformation($"Digital Twin {dt.Id} created.");
                return dt.Id;
            }
        }
    
        /// <summary>
        /// Expected function result format
        /// </summary>
        public class ResponseObj
        {
            public string iotHubHostName { get; set; }
            public TwinState initialTwin { get; set; }
        }
    }
    
  4. Publique el proyecto con la función DpsAdtAllocationFunc.cs en la aplicación de funciones en 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.

Importante

La primera vez que se crea la aplicación de funciones en la sección de requisitos previos, es posible que ya se haya asignado un rol de acceso para la función y se haya configurado la aplicación para que acceda a la instancia de Azure Digital Twins. Estos deben realizarse una vez para toda la aplicación de función, por lo que debe comprobar que se han completado en la aplicación antes de continuar. Puede encontrar instrucciones en la sección Configuración de la aplicación publicada del artículo Escritura de código de autenticación de aplicaciones.

Creación de una inscripción de Device Provisioning Service

A continuación, deberá crear una inscripción en Device Provisioning Service mediante una función de asignación personalizada. Para crear una inscripción, siga las instrucciones de la sección Creación de la inscripción del artículo directivas de asignación personalizadas de la documentación del servicio aprovisionamiento de dispositivos.

Al pasar por ese flujo, asegúrese de seleccionar las opciones siguientes para vincular la inscripción a la función que ha creado.

  • Seleccione cómo quiere asignar los dispositivos a los centros: Personalizado (usar una función de Azure).
  • Seleccione los centros de IoT a los que se puede asignar este grupo: elija el nombre del centro de IoT o seleccione el botón Vincular un nuevo centro de IoT y elija su centro de IoT en las opciones.

A continuación, elija el botón Seleccionar una función nueva para vincular la aplicación de función al grupo de inscripción. Después, rellene los siguientes valores:

  • Suscripción: la suscripción de Azure se rellena automáticamente. Asegúrese de que es la suscripción correcta.
  • Aplicación de funciones:elija el nombre de la aplicación de funciones.
  • Función: elija DpsAdtAllocationFunc.

Guarde sus detalles.

Captura de pantalla de la ventana de detalles del grupo de inscripción Customs en Azure Portal.

Después de crear la inscripción, selecciónela para ver su configuración. Copie la clave principal de la inscripción, que se usará más adelante en este artículo para configurar el simulador de dispositivos.

Configuración del simulador de dispositivos

En este ejemplo se usa un simulador de dispositivos que incluye el aprovisionamiento mediante Device Provisioning Service. El simulador de dispositivos se encuentra en el ejemplo de integración de Azure Digital Twins e IoT Hub que descargó en la sección de requisitos previos.

Carga del modelo

El simulador de dispositivos es un dispositivo de tipo termostato que usa el modelo con este identificador: dtmi:contosocom:DigitalTwins:Thermostat;1. Tendrá que cargar este modelo en Azure Digital Twins para poder crear un gemelo de este tipo para el dispositivo.

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.

Para más información sobre los modelos, consulte Administración de modelos.

Configuración y ejecución del simulador

En una ventana de comandos de la máquina local, vaya al ejemplo descargado Azure Digital Twins e Integración de IoT Hub que descomprimió anteriormente y, a continuación, en el directorio device-simulator . Luego, instale las dependencias del proyecto mediante el siguiente comando:

npm install

Después, en el directorio del simulador de dispositivos, copie el archivo. env.template en un archivo nuevo denominado . env y recopile los siguientes valores para rellenar la configuración:

  • PROVISIONING_IDSCOPE: para obtener este valor, vaya al servicio de aprovisionamiento de dispositivos en Azure Portal, seleccione Información general en las opciones de menú y busque el ámbito de identificador de campo.

    Captura de pantalla de la vista de Azure Portal de la página información general de aprovisionamiento de dispositivos que resalta el valor de Ámbito de id.

  • PROVISIONING_REGISTRATION_ID: puede elegir un identificador de registro para el dispositivo.

  • ADT_MODEL_ID: dtmi:contosocom:DigitalTwins:Thermostat;1

  • PROVISIONING_SYMMETRIC_KEY: esta variable de entorno es la clave principal de la inscripción que configuró anteriormente. Para obtener este valor de nuevo, vaya al servicio de aprovisionamiento de dispositivos en el Azure Portal, seleccione administrar inscripcionesy, luego, seleccione el grupo de inscripción que creó anteriormente y copie la clave principal.

    Captura de pantalla de la vista de Azure Portal de la página de inscripciones de administración de Device Provisioning Service que resalta el valor de la clave principal de SAS.

Ahora, use los valores anteriores para actualizar la configuración del archivo. .env.

PROVISIONING_HOST = "global.azure-devices-provisioning.net"
PROVISIONING_IDSCOPE = "<Device-Provisioning-Service-Scope-ID>"
PROVISIONING_REGISTRATION_ID = "<Device-Registration-ID>"
ADT_MODEL_ID = "dtmi:contosocom:DigitalTwins:Thermostat;1"
PROVISIONING_SYMMETRIC_KEY = "<Device-Provisioning-Service-enrollment-primary-SAS-key>"

Guarde y cierre el archivo.

Iniciar ejecución del simulador de dispositivos

Todavía en el directorio device-simulator de la ventana de comandos, inicie el simulador de dispositivos mediante el comando siguiente:

node .\adt_custom_register.js

Debería ver que el dispositivo se registra y se conecta a IoT Hub y, a continuación, comienza a enviar mensajes. Captura de pantalla de la ventana Comandos que muestra el registro de dispositivos y el envío de mensajes.

Validación

El flujo que ha configurado en este artículo derivará en el registro automático del dispositivo en Azure Digital Twins. Use el siguiente comando de la CLI de Azure Digital Twins para buscar el gemelo del dispositivo de la instancia de Azure Digital Twins que ha creado. Existe un marcador de posición para el nombre de host de la instancia (también se puede usar el nombre descriptivo de la instancia con una ligera disminución del rendimiento), y un marcador de posición para el identificador de registro del dispositivo.

az dt twin show --dt-name <instance-hostname-or-name> --twin-id "<device-registration-ID>"

Debería ver el gemelo del dispositivo que se encuentra en la instancia de Azure Digital Twins. Captura de pantalla del ventana Comandos mostrando gemelas recién creados.

Retirada automática del dispositivo mediante eventos de ciclo de vida de IoT Hub

En esta sección va a asociar los eventos de ciclo de vida de IoT Hub a Azure Digital Twins para retirar automáticamente los dispositivos mediante la ruta de acceso siguiente. Este diagrama es un extracto de la arquitectura completa que se ha mostrado anteriormente.

Diagrama del flujo de retirada de dispositivo: un extracto del diagrama de la arquitectura de la solución, que sigue los datos de la eliminación de un dispositivo en Azure Digital Twins.

Esta es una descripción del flujo del proceso:

  1. Un proceso externo o manual desencadena la eliminación de un dispositivo en IoT Hub.
  2. IoT Hub elimina el dispositivo y genera un evento de ciclo de vida de dispositivo que se va a enrutar a un centro de eventos.
  3. Una función de Azure elimina el gemelo del dispositivo en Azure Digital Twins.

En las siguientes secciones se describen los pasos necesarios para configurar este flujo de retirada automática del dispositivo.

Creación de un centro de eventos

A continuación, crearás un centro de eventos de Azure para recibir los eventos del ciclo de vida de IoT Hub.

Siga los pasos descritos en el inicio rápido para crear un centro de eventos. Asigne un nombre lifecycleevents al centro de eventos. Usará este nombre de centro de eventos al configurar la ruta IoT Hub y una función de Azure en las secciones siguientes.

En la captura de pantalla siguiente se muestra la creación del centro de eventos. Captura de pantalla de la ventana de Azure Portal que muestra cómo crear un centro de eventos con el nombre lifecycleevents.

Creación de una directiva SAS para el centro de eventos

A continuación, deberá crear una directiva de firma de acceso compartido (SAS) para configurar el centro de eventos con la aplicación de función. Para crear la directiva de SAS:

  1. Vaya al centro de eventos que ha creado en Azure Portal y seleccione Directivas de acceso compartido en las opciones de menú de la izquierda.
  2. Seleccione Agregar. En la ventana Agregar Directiva SAS que se abre, escriba un nombre de directiva de su elección y active la casilla escuchar.
  3. Seleccione Crear.

Captura de pantalla de Azure Portal que muestra cómo agregar una directiva SAS del centro de eventos.

Configurar el centro de eventos con la aplicación de funciones

Después, configure la aplicación de funciones de Azure que configuró en la sección de requisitos previos para trabajar con el nuevo centro de eventos. La función se configura al establecer una variable de entorno dentro de la aplicación de funciones con la cadena de conexión del centro de eventos.

  1. Abra la directiva que ha creado y copie el valor de Cadena de conexión: clave principal.

    Captura de pantalla de Azure Portal que muestra cómo copiar la cadena de conexión: clave principal.

  2. Agregue la cadena de conexión como una variable en la configuración de la aplicación de función con el siguiente comando de CLI de Azure. El comando se puede ejecutar en Cloud Shell, o bien localmente si tiene la CLI de Azure está instalada en la máquina.

    az functionapp config appsettings set --settings "EVENTHUB_CONNECTIONSTRING=<Event-Hubs-SAS-connection-string-Listen>" --resource-group <resource-group> --name <your-function-app-name>
    

Agregar una función para retirar con eventos de ciclo de vida de IoT Hub

En el proyecto de aplicación de funciones que creó en la sección de requisitos previos, creará una función para retirar un dispositivo existente mediante eventos del ciclo de vida de IoT Hub.

Para más información sobre los eventos de ciclo de vida, consulte Eventos que no son de telemetría de IoT Hub. Para más información sobre cómo usar Event Hubs con funciones de Azure, consulte Desencadenador de Azure Event Hubs para Azure Functions.

Vaya al proyecto de aplicación de función ubicado en la máquina y siga los pasos que se describen a continuación.

  1. Primero, cree una función de tipo Desencadenador del centro de eventos en el proyecto de aplicación de funciones.

  2. Agregue un nuevo paquete de NuGet al proyecto: Microsoft.Azure.Devices.Provisioning.Service. Es posible que también tenga que agregar más paquetes al proyecto si los paquetes usados en el código ya no forman parte del proyecto.

  3. En el archivo de código de la función recién creada, pegue el código siguiente, denomínela con el nombre DeleteDeviceInTwinFunc.cs y guarde el archivo.

    // Copyright (c) Microsoft. All rights reserved.
    // Licensed under the MIT license. See LICENSE file in the project root for full license information.
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Threading.Tasks;
    using Azure;
    using Azure.Core.Pipeline;
    using Azure.DigitalTwins.Core;
    using Azure.Identity;
    using Microsoft.Azure.EventHubs;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Extensions.Logging;
    
    namespace Samples.AdtIothub
    {
        public static class DeleteDeviceInTwinFunc
        {
            private static string adtAppId = "https://digitaltwins.azure.net";
            private static readonly string adtInstanceUrl = Environment.GetEnvironmentVariable("ADT_SERVICE_URL", EnvironmentVariableTarget.Process);
            private static readonly HttpClient singletonHttpClientInstance = new HttpClient();
    
            [FunctionName("DeleteDeviceInTwinFunc")]
            public static async Task Run(
                [EventHubTrigger("lifecycleevents", Connection = "EVENTHUB_CONNECTIONSTRING")] EventData[] events, ILogger log)
            {
                var exceptions = new List<Exception>(events.Length);
    
                // Create Digital Twin client
                var cred = new ManagedIdentityCredential(adtAppId);
                var client = new DigitalTwinsClient(
                    new Uri(adtInstanceUrl),
                    cred,
                    new DigitalTwinsClientOptions
                    {
                        Transport = new HttpClientTransport(singletonHttpClientInstance)
                    });
    
                foreach (EventData eventData in events)
                {
                    try
                    {
                        //log.LogDebug($"EventData: {System.Text.Json.JsonSerializer.Serialize(eventData)}");
    
                        string opType = eventData.Properties["opType"] as string;
                        if (opType == "deleteDeviceIdentity")
                        {
                            string deviceId = eventData.Properties["deviceId"] as string;
    
                            try
                            {
                                // Find twin based on the original Registration ID
                                BasicDigitalTwin digitalTwin = await client.GetDigitalTwinAsync<BasicDigitalTwin>(deviceId);
    
                                // In order to delete the twin, all relationships must first be removed
                                await DeleteAllRelationshipsAsync(client, digitalTwin.Id, log);
    
                                // Delete the twin
                                await client.DeleteDigitalTwinAsync(digitalTwin.Id, digitalTwin.ETag);
                                log.LogInformation($"Twin {digitalTwin.Id} deleted in DT");
                            }
                            catch (RequestFailedException e) when (e.Status == (int)HttpStatusCode.NotFound)
                            {
                                log.LogWarning($"Twin {deviceId} not found in DT");
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        // We need to keep processing the rest of the batch - capture this exception and continue.
                        exceptions.Add(e);
                    }
                }
    
                if (exceptions.Count > 1)
                    throw new AggregateException(exceptions);
    
                if (exceptions.Count == 1)
                    throw exceptions.Single();
            }
    
            /// <summary>
            /// Deletes all outgoing and incoming relationships from a specified digital twin
            /// </summary>
            public static async Task DeleteAllRelationshipsAsync(DigitalTwinsClient client, string dtId, ILogger log)
            {
                AsyncPageable<BasicRelationship> relationships = client.GetRelationshipsAsync<BasicRelationship>(dtId);
                await foreach (BasicRelationship relationship in relationships)
                {
                    await client.DeleteRelationshipAsync(dtId, relationship.Id, relationship.ETag);
                    log.LogInformation($"Twin {dtId} relationship {relationship.Id} deleted in DT");
                }
    
                AsyncPageable<IncomingRelationship> incomingRelationships = client.GetIncomingRelationshipsAsync(dtId);
                await foreach (IncomingRelationship incomingRelationship in incomingRelationships)
                {
                    await client.DeleteRelationshipAsync(incomingRelationship.SourceId, incomingRelationship.RelationshipId);
                    log.LogInformation($"Twin {dtId} incoming relationship {incomingRelationship.RelationshipId} from {incomingRelationship.SourceId} deleted in DT");
                }
            }
        }
    }
    
  4. Publique el proyecto con la función DeleteDeviceInTwinFunc.cs en una aplicación de funciones en 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.

Importante

La primera vez que se crea la aplicación de funciones en la sección de requisitos previos, es posible que ya se haya asignado un rol de acceso para la función y se haya configurado la aplicación para que acceda a la instancia de Azure Digital Twins. Estos deben realizarse una vez para toda la aplicación de función, por lo que debe comprobar que se han completado en la aplicación antes de continuar. Puede encontrar instrucciones en la sección Configuración de la aplicación publicada del artículo Escritura de código de autenticación de aplicaciones.

Creación de una ruta de IoT Hub para eventos de ciclo de vida

Ahora configurará una ruta de IoT Hub para enrutar los eventos de ciclo de vida del dispositivo. En este caso, escuchará específicamente los eventos de eliminación de dispositivos, que se identifican mediante if (opType == "deleteDeviceIdentity"). Este evento desencadenará la eliminación del elemento gemelo digital, finalizando la retirada del dispositivo y de su gemelo digital.

En primer lugar, deberá crear un punto de conexión del centro de eventos en el centro de IoT. A continuación, agregará una ruta en IoT hub para enviar eventos de ciclo de vida a este punto de conexión del centro de eventos. Siga estos pasos para crear un punto de conexión del centro de eventos:

  1. En Azure Portal, vaya a la instancia de IoT Hub que creó en la sección de requisitos previos y seleccione Enrutamiento de mensajes en las opciones de menú de la izquierda.

  2. Seleccione la pestaña Puntos de conexión personalizados.

  3. Seleccione + Agregar y elija Event Hubs para agregar un punto de conexión de tipo de Event Hubs.

    Captura de pantalla de Azure Portal en la que se muestra cómo agregar un punto de conexión personalizado de Event Hubs.

  4. En la ventana Agregar un punto de conexión del centro de eventos que se abre, elija los siguientes valores:

    • Nombre del punto de conexión: elija un nombre de punto de conexión.
    • Espacio de nombres del centro de eventos: seleccione el espacio de nombres del centro de eventos en la lista desplegable.
    • Instancia de centro de eventos: elija el nombre del centro de eventos que creó en el paso anterior.
  5. Seleccione Crear. Mantenga esta ventana abierta para agregar una ruta en el paso siguiente.

    Captura de pantalla de Azure Portal en la que se muestra cómo agregar un punto de conexión del centro de eventos.

A continuación, agregará una ruta que se conecta al punto de conexión que creó en el paso anterior, con una consulta de enrutamiento que envía los eventos de eliminación. Siga estos pasos para crear una ruta:

  1. Vaya a la pestaña rutas y seleccione Agregar para agregar una ruta.

    Captura de pantalla de Azure Portal que muestra cómo agregar una ruta para enviar eventos.

  2. En la página Agregar una ruta que se abre, elija los siguientes valores:

    • Nombre: elija un nombre para el módulo.
    • Punto de conexión: elija el punto de conexión de Event Hubs que creó anteriormente en la lista desplegable.
    • Origen de datos: elija eventos del ciclo de vida del dispositivo.
    • Consulta de enrutamiento: Escriba opType='deleteDeviceIdentity'. Esta consulta limita los eventos de ciclo de vida del dispositivo para enviar solo los eventos de eliminación.
  3. Seleccione Guardar.

    Captura de pantalla de Azure Portal que muestra cómo agregar una ruta para enviar eventos del ciclo de vida.

Una vez que haya pasado por este flujo, todo estará listo para la completa retirada de los dispositivos.

Validación

Para desencadenar el proceso de retirada, debe eliminar manualmente el dispositivo de IoT Hub.

Puede eliminar manualmente el dispositivo desde IoT Hub con un comando de la CLI de Azure o desde Azure Portal. Siga los siguientes pasos para eliminar el dispositivo en Azure Portal:

  1. Vaya a IoT Hub y elija dispositivos IoT en las opciones de menú de la izquierda.
  2. Verá un dispositivo con el identificador de registro de dispositivo que eligió en la primera mitad de este artículo. También puede elegir cualquier otro dispositivo que desee eliminar, siempre que tenga un gemelo en Azure Digital Twins, de modo que pueda comprobar que el gemelo se elimina automáticamente después de eliminar el dispositivo.
  3. Seleccione el dispositivo y elija Eliminar.

Captura de pantalla del Azure Portal que muestra cómo eliminar el dispositivo gemelo de los dispositivos IoT.

Puede tardar unos minutos en ver los cambios reflejados en Azure Digital Twins.

Use el siguiente comando de la CLI de Azure Digital Twins para comprobar el gemelo del dispositivo de la instancia de Azure Digital Twins que ha eliminado. Existe un marcador de posición para el nombre de host de la instancia (también se puede usar el nombre descriptivo de la instancia con una ligera disminución del rendimiento), y un marcador de posición para el identificador de registro del dispositivo.

az dt twin show --dt-name <instance-hostname-or-name> --twin-id "<device-registration-ID>"

Debería ver que el gemelo del dispositivo ya no se encuentra en la instancia de Azure Digital Twins.

Captura de pantalla ventana Comandos que muestra que ya no se encuentra el gemelo.

Limpieza de recursos

Cuando ya no necesite los recursos creados en este artículo, siga estos pasos para eliminarlos.

Con Azure Cloud Shell o la CLI de Azure local, puede eliminar todos los recursos de Azure de un grupo de recursos mediante el comando az group delete. Este comando permite eliminar el grupo de recursos, la instancia de Azure Digital Twins, el centro de IoT y el registro del dispositivo del centro de conectividad, el tema de Event Grid y las suscripciones asociadas, y el espacio de nombres de Event Hubs y ambas aplicaciones de Azure Functions, incluidos los recursos asociados, como el almacenamiento.

Importante

La eliminación de un grupo de recursos es irreversible. El grupo de recursos y todos los recursos contenidos en él se eliminan permanentemente. Asegúrese de no eliminar por accidente el grupo de recursos o los recursos equivocados.

az group delete --name <your-resource-group>

Por último, elimine la carpeta de ejemplo del proyecto que descargó de la máquina local.

Pasos siguientes

Los gemelos digitales que se han creado para los dispositivos se almacenan como una jerarquía plana en Azure Digital Twins, pero se pueden enriquecer con la información del modelo y una jerarquía de varios niveles para la organización. Para más información sobre este concepto, consulte:

Para más información sobre cómo usar solicitudes HTTP con funciones de Azure, consulte:

Puede escribir la lógica personalizada para proporcionar automáticamente esta información con los datos del modelo y del gráfico ya almacenados en Azure Digital Twins. Para más información sobre cómo administrar, actualizar y recuperar información del grafo de gemelos, consulte las guías paso a paso siguientes: