Share via


Gerenciar automaticamente dispositivos no Azure Digital Twins usando o Serviço de Provisionamento de Dispositivo (DPS)

Neste artigo, você aprenderá a integrar os Gêmeos Digitais do Azure ao DPS (Serviço de Provisionamento de Dispositivos).

A solução descrita neste artigo permitirá automatizar o processo de provisionamento e desativação de dispositivos do Hub IoT no Azure Digital Twins, usando o Serviço de Provisionamento de Dispositivos.

Para obter mais informações sobre os estágios de provisionamento e desativação e para entender melhor o conjunto de estágios gerais de gerenciamento de dispositivos que são comuns a todos os projetos corporativos de IoT, consulte a seção Ciclo de vida do dispositivo da documentação de gerenciamento de dispositivos do Hub IoT.

Pré-requisitos

Antes de configurar o provisionamento, você precisará configurar os seguintes recursos:

  • Uma instância do Azure Digital Twins. Siga as instruções em Configurar uma instância e autenticação para criar uma instância de gêmeos digitais do Azure. Reúna o nome do host da instância no portal do Azure (instruções).
  • Um hub IoT. Para obter instruções, consulte a seção "Criar um Hub IoT" do Guia de início rápido do Hub IoT.
  • Uma função do Azure que atualiza informações de gêmeos digitais com base em dados do Hub IoT. Siga as instruções em Ingest IoT hub data para criar esta função do Azure. Reúna o nome da função para usá-lo neste artigo.

Este exemplo também usa um simulador de dispositivo que inclui provisionamento usando o Serviço de Provisionamento de Dispositivo. O simulador de dispositivo está localizado aqui: Azure Digital Twins e Exemplo de Integração do Hub IoT. Obtenha o projeto de exemplo em sua máquina navegando até o repositório GitHub para o exemplo, que você pode baixar como um arquivo .zip selecionando o botão Código e Baixar ZIP.

Screenshot of the digital-twins-iothub-integration repo on GitHub, highlighting the steps to download it as a zip.

Descompacte a pasta baixada.

Você precisará do Node.js instalado em sua máquina. O simulador de dispositivo é baseado no Node.js, versão 10.0.x ou posterior.

Arquitetura de soluções

Esta solução inclui etapas para provisionar e desativar um dispositivo no Azure Digital Twins, usando o Serviço de Provisionamento de Dispositivo.

Para alocar dispositivos na solução, os dados fluem entre um dispositivo termostato e DPS. Em seguida, os dados fluem do DPS para o Hub IoT e para os Gêmeos Digitais do Azure por meio de uma função do Azure.

Para desativar um dispositivo, os dados de uma exclusão manual de dispositivo fluem para os Gêmeos Digitais do Azure por meio do Hub IoT, Hubs de Eventos e uma função do Azure.

A imagem abaixo ilustra essa arquitetura.

Diagram of device and several Azure services in an end-to-end scenario showing the data flow.

Este artigo está dividido em duas seções, cada uma focada em uma parte dessa arquitetura completa:

Dispositivo de provisionamento automático usando o Serviço de Provisionamento de Dispositivo

Nesta seção, você anexará o Serviço de Provisionamento de Dispositivos aos Gêmeos Digitais do Azure para provisionar dispositivos automaticamente pelo caminho abaixo. Este diagrama é um trecho da arquitetura completa mostrada anteriormente.

Diagram of Provision flow—an excerpt of the solution architecture diagram following data from a thermostat into Azure Digital Twins.

Aqui está uma descrição do fluxo do processo:

  1. O dispositivo entra em contato com o ponto de extremidade DPS, passando informações de identificação para provar sua identidade.
  2. O DPS valida a identidade do dispositivo validando a ID e a chave de registro em relação à lista de registro e chama uma função do Azure para fazer a alocação.
  3. A função do Azure cria um novo gêmeo nos Gêmeos Digitais do Azure para o dispositivo. O gémeo terá o mesmo nome que o ID de registo do dispositivo.
  4. O DPS registra o dispositivo com um hub IoT e preenche o estado gêmeo escolhido do dispositivo.
  5. O hub IoT retorna informações de ID do dispositivo e as informações de conexão do hub IoT para o dispositivo. O dispositivo agora pode se conectar ao hub IoT.

As seções a seguir percorrem as etapas para configurar esse fluxo de dispositivo de provisionamento automático.

Criar um serviço de provisionamento de dispositivo

Quando um novo dispositivo é provisionado usando o Serviço de Provisionamento de Dispositivo, um novo gêmeo para esse dispositivo pode ser criado no Azure Digital Twins com o mesmo nome da ID de registro.

Crie uma instância do Serviço de Provisionamento de Dispositivo, que será usada para provisionar dispositivos IoT. Você pode usar as instruções da CLI do Azure abaixo ou usar o portal do Azure seguindo Configurar o Serviço de Provisionamento de Dispositivo do Hub IoT com o portal do Azure.

O comando da CLI do Azure a seguir criará um Serviço de Provisionamento de Dispositivo. Você precisará especificar um nome de Serviço de Provisionamento de Dispositivo, grupo de recursos e região. Para ver quais regiões oferecem suporte ao Serviço de Provisionamento de Dispositivos, visite os produtos do Azure disponíveis por região. O comando pode ser executado no Cloud Shell ou localmente se você tiver a CLI do Azure instalada em sua máquina.

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

Adicionar uma função para usar com o Serviço de Provisionamento de Dispositivos

Dentro do seu projeto de aplicativo de função que você criou na seção Pré-requisitos, você criará uma nova função para usar com o Serviço de Provisionamento de Dispositivo. Essa função será usada pelo Serviço de Provisionamento de Dispositivo em uma Política de Alocação Personalizada para provisionar um novo dispositivo.

Navegue até o projeto de aplicativo de função em sua máquina e siga as etapas abaixo.

  1. Primeiro, crie uma nova função do tipo HTTP-trigger no projeto de aplicativo de função.

  2. Adicione um novo pacote NuGet ao projeto: Microsoft.Azure.Devices.Provisioning.Service. Talvez seja necessário adicionar mais pacotes ao seu projeto também, se os pacotes usados no código ainda não fizerem parte do projeto.

  3. No arquivo de código de função recém-criado, cole o código a seguir, nomeie a função DpsAdtAllocationFunc.cs e salve o arquivo.

    // 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 o projeto com a função DpsAdtAllocationFunc.cs em um aplicativo de função no Azure.

    Para obter instruções sobre como publicar a função usando o Visual Studio, consulte Desenvolver funções do Azure usando o Visual Studio. Para obter instruções sobre como publicar a função usando o Visual Studio Code, consulte Criar uma função C# no Azure usando o Visual Studio Code. Para obter instruções sobre como publicar a função usando a CLI do Azure, consulte Criar uma função C# no Azure a partir da linha de comando.

Importante

Ao criar o aplicativo de função pela primeira vez na seção Pré-requisitos, você já pode ter atribuído uma função de acesso para a função e configurado as configurações do aplicativo para que ela acesse sua instância do Azure Digital Twins. Isso precisa ser feito uma vez para todo o aplicativo de função, portanto, verifique se eles foram concluídos em seu aplicativo antes de continuar. Você pode encontrar instruções na seção Configurar aplicativo publicado do artigo Escrever código de autenticação de aplicativo.

Criar registro de provisionamento de dispositivo

Em seguida, você precisará criar um registro no Serviço de Provisionamento de Dispositivo usando uma função de alocação personalizada. Para criar um registro, siga as instruções na seção Criar o registro do artigo de políticas de alocação personalizadas na documentação do Serviço de Provisionamento de Dispositivos.

Ao passar por esse fluxo, certifique-se de selecionar as seguintes opções para vincular o registro à função que você criou.

  • Selecione como deseja atribuir dispositivos a hubs: Personalizado (Usar Função do Azure).
  • Selecione os hubs IoT aos quais esse grupo pode ser atribuído: Escolha o nome do hub IoT ou selecione o botão Vincular um novo hub IoT e escolha seu hub IoT entre as opções.

Em seguida, escolha o botão Selecionar uma nova função para vincular seu aplicativo de função ao grupo de registro. Em seguida, preencha os seguintes valores:

  • Assinatura: sua assinatura do Azure é preenchida automaticamente. Certifique-se de que é a subscrição certa.
  • Aplicativo de função: escolha o nome do aplicativo de função.
  • Função: Escolha DpsAdtAllocationFunc.

Guarde os seus dados.

Screenshot of the Customs enrollment group details window in the Azure portal.

Depois de criar o registro, selecione-o para visualizar suas configurações. Copie a Chave Primária para o registro, que será usada posteriormente neste artigo para configurar o simulador de dispositivo.

Configurar o simulador de dispositivos

Este exemplo usa um simulador de dispositivo que inclui provisionamento usando o Serviço de Provisionamento de Dispositivo. O simulador de dispositivo está localizado no Exemplo de Integração de Gêmeos Digitais e Hub IoT do Azure que você baixou na seção Pré-requisitos.

Carregue o modelo

O simulador de dispositivo é um dispositivo do tipo termostato que usa o modelo com este ID: dtmi:contosocom:DigitalTwins:Thermostat;1. Você precisará carregar esse modelo no Azure Digital Twins antes de criar um gêmeo desse tipo para o dispositivo.

O modelo tem o seguinte aspeto:

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

Para carregar esse modelo em sua instância de gêmeos, execute o seguinte comando da CLI do Azure, que carrega o modelo acima como JSON embutido. Você pode executar o comando no Azure Cloud Shell em seu navegador (use o ambiente Bash) ou em sua máquina se tiver a CLI instalada localmente. Há um espaço reservado para o nome do host da instância (você também pode usar o nome amigável da instância com uma ligeira diminuição no desempenho).

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

Se você estiver usando algo diferente do Cloud Shell no ambiente Bash, talvez seja necessário escapar de certos caracteres no JSON embutido para que ele seja analisado corretamente. Para obter mais informações, consulte Usar caracteres especiais em shells diferentes.

Para obter mais informações sobre modelos, consulte Gerenciar modelos.

Configurar e executar o simulador

Em uma janela de comando em sua máquina local, navegue até o exemplo baixado Azure Digital Twins and IoT Hub Integration que você descompactou anteriormente e, em seguida, para o diretório device-simulator. Em seguida, instale as dependências para o projeto usando o seguinte comando:

npm install

Em seguida, no diretório do simulador de dispositivo, copie o arquivo .env.template para um novo arquivo chamado .env e reúna os seguintes valores para preencher as configurações:

  • PROVISIONING_IDSCOPE: Para obter esse valor, navegue até o serviço de provisionamento de dispositivo no portal do Azure, selecione Visão geral nas opções de menu e procure o campo ID Escopo.

    Screenshot of the Azure portal view of the device provisioning overview page highlighting the ID Scope value.

  • PROVISIONING_REGISTRATION_ID: Pode escolher um ID de registo para o seu dispositivo.

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

  • PROVISIONING_SYMMETRIC_KEY: Essa variável de ambiente é a chave primária para o registro configurado anteriormente. Para obter esse valor novamente, navegue até o serviço de provisionamento de dispositivo no portal do Azure, selecione Gerenciar inscrições e, em seguida, selecione o grupo de inscrição criado anteriormente e copie a Chave Primária.

    Screenshot of the Azure portal view of the device provisioning service manage enrollments page highlighting the SAS primary key value.

Agora, use os valores acima para atualizar as configurações do arquivo .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 e feche o ficheiro.

Comece a executar o simulador de dispositivo

Ainda no diretório device-simulator na janela de comando, inicie o simulador de dispositivo usando o seguinte comando:

node .\adt_custom_register.js

Você verá o dispositivo sendo registrado e conectado ao Hub IoT e, em seguida, começando a enviar mensagens. Screenshot of the Command window showing device registration and sending messages.

Validar

O fluxo que você configurou neste artigo resultará no registro automático do dispositivo nos Gêmeos Digitais do Azure. Use o seguinte comando da CLI dos Gêmeos Digitais do Azure para localizar o gêmeo do dispositivo na instância dos Gêmeos Digitais do Azure que você criou. Há um espaço reservado para o nome do host da instância (você também pode usar o nome amigável da instância com uma ligeira diminuição no desempenho) e um espaço reservado para a ID de registro do dispositivo.

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

Você deve ver o gêmeo do dispositivo sendo encontrado na instância do Azure Digital Twins. Screenshot of the Command window showing newly created twin.

Desativar automaticamente o dispositivo usando eventos do ciclo de vida do Hub IoT

Nesta seção, você anexará eventos do ciclo de vida do Hub IoT aos Gêmeos Digitais do Azure para desativar automaticamente os dispositivos pelo caminho abaixo. Este diagrama é um trecho da arquitetura completa mostrada anteriormente.

Diagram of the Retire device flow—an excerpt of the solution architecture diagram, following data from a device deletion into Azure Digital Twins.

Aqui está uma descrição do fluxo do processo:

  1. Um processo externo ou manual aciona a exclusão de um dispositivo no Hub IoT.
  2. O Hub IoT exclui o dispositivo e gera um evento do ciclo de vida do dispositivo que será roteado para um hub deeventos.
  3. Uma função do Azure exclui o gêmeo do dispositivo nos Gêmeos Digitais do Azure.

As seções a seguir percorrem as etapas para configurar esse fluxo de dispositivo de retirada automática.

Criar um hub de eventos

Em seguida, você criará um hub de eventos do Azure para receber eventos do ciclo de vida do Hub IoT.

Siga as etapas descritas no Guia de início rápido Criar um hub de eventos. Nomeie seus eventos de ciclo de vida do hub de eventos. Você usará esse nome de hub de eventos ao configurar a rota do Hub IoT e uma função do Azure nas próximas seções.

A captura de tela abaixo ilustra a criação do hub de eventos. Screenshot of the Azure portal window showing how to create an event hub with the name lifecycleevents.

Criar política SAS para o seu hub de eventos

Em seguida, você precisará criar uma política de assinatura de acesso compartilhado (SAS) para configurar o hub de eventos com seu aplicativo de função. Para criar a política SAS:

  1. Navegue até o hub de eventos criado no portal do Azure e selecione Políticas de acesso compartilhado nas opções de menu à esquerda.
  2. Selecione Adicionar. Na janela Adicionar Política SAS que se abre, introduza um nome de política à sua escolha e selecione a caixa de verificação Ouvir.
  3. Selecione Criar.

Screenshot of the Azure portal showing how to add an event hub SAS policy.

Configurar o hub de eventos com o aplicativo de função

Em seguida, configure o aplicativo de função do Azure que você configurou na seção Pré-requisitos para trabalhar com seu novo hub de eventos. Você configurará a função definindo uma variável de ambiente dentro do aplicativo de função com a cadeia de conexão do hub de eventos.

  1. Abra a política que você criou e copie o valor da chave primária da cadeia de conexão.

    Screenshot of the Azure portal showing how to copy the connection string-primary key.

  2. Adicione a cadeia de conexão como uma variável nas configurações do aplicativo de função com o seguinte comando da CLI do Azure. O comando pode ser executado no Cloud Shell ou localmente se você tiver a CLI do Azure instalada em sua 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>
    

Adicionar uma função para desativar com eventos do ciclo de vida do Hub IoT

Dentro do seu projeto de aplicativo de função que você criou na seção Pré-requisitos, você criará uma nova função para desativar um dispositivo existente usando eventos do ciclo de vida do Hub IoT.

Para obter mais informações sobre eventos de ciclo de vida, consulte Eventos não telemétricos do Hub IoT. Para obter mais informações sobre como usar Hubs de Eventos com funções do Azure, consulte Gatilho de Hubs de Eventos do Azure para Azure Functions.

Navegue até o projeto de aplicativo de função em sua máquina e siga as etapas abaixo.

  1. Primeiro, crie uma nova função do tipo Event Hub Trigger no projeto de aplicativo de função.

  2. Adicione um novo pacote NuGet ao projeto: Microsoft.Azure.Devices.Provisioning.Service. Talvez seja necessário adicionar mais pacotes ao seu projeto também, se os pacotes usados no código ainda não fizerem parte do projeto.

  3. No arquivo de código de função recém-criado, cole o código a seguir, nomeie a função DeleteDeviceInTwinFunc.cs e salve o arquivo.

    // 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 o projeto com a função DeleteDeviceInTwinFunc.cs em um aplicativo de função no Azure.

    Para obter instruções sobre como publicar a função usando o Visual Studio, consulte Desenvolver funções do Azure usando o Visual Studio. Para obter instruções sobre como publicar a função usando o Visual Studio Code, consulte Criar uma função C# no Azure usando o Visual Studio Code. Para obter instruções sobre como publicar a função usando a CLI do Azure, consulte Criar uma função C# no Azure a partir da linha de comando.

Importante

Ao criar o aplicativo de função pela primeira vez na seção Pré-requisitos, você já pode ter atribuído uma função de acesso para a função e configurado as configurações do aplicativo para que ela acesse sua instância do Azure Digital Twins. Isso precisa ser feito uma vez para todo o aplicativo de função, portanto, verifique se eles foram concluídos em seu aplicativo antes de continuar. Você pode encontrar instruções na seção Configurar aplicativo publicado do artigo Escrever código de autenticação de aplicativo.

Criar uma rota do Hub IoT para eventos do ciclo de vida

Agora você configurará uma rota do Hub IoT para rotear eventos do ciclo de vida do dispositivo. Nesse caso, você ouvirá especificamente os eventos de exclusão de dispositivo, identificados por if (opType == "deleteDeviceIdentity"). Este evento irá desencadear a exclusão do item gêmeo digital, completando o processo de aposentadoria de um dispositivo e seu gêmeo digital.

Primeiro, você precisará criar um ponto de extremidade de hub de eventos em seu hub IoT. Em seguida, você adicionará uma rota no hub IoT para enviar eventos de ciclo de vida para esse ponto de extremidade do hub de eventos. Siga estas etapas para criar um ponto de extremidade do hub de eventos:

  1. No portal do Azure, navegue até o hub IoT criado na seção Pré-requisitos e selecione Roteamento de mensagens nas opções de menu à esquerda.

  2. Selecione a guia Pontos de extremidade personalizados.

  3. Selecione + Adicionar e escolha Hubs de eventos para adicionar um ponto de extremidade do tipo Hubs de Eventos.

    Screenshot of the Azure portal showing how to add an Event Hubs custom endpoint.

  4. Na janela Adicionar um ponto de extremidade do hub de eventos que se abre, escolha os seguintes valores:

    • Nome do ponto de extremidade: escolha um nome de ponto final.
    • Namespace do hub de eventos: selecione o namespace do hub de eventos na lista suspensa.
    • Instância do hub de eventos: escolha o nome do hub de eventos que você criou na etapa anterior.
  5. Selecione Criar. Mantenha esta janela aberta para adicionar uma rota na próxima etapa.

    Screenshot of the Azure portal showing how to add an event hub endpoint.

Em seguida, você adicionará uma rota que se conecta ao ponto de extremidade criado na etapa acima, com uma consulta de roteamento que envia os eventos de exclusão. Siga estas etapas para criar uma rota:

  1. Navegue até a guia Rotas e selecione Adicionar para adicionar uma rota.

    Screenshot of the Azure portal showing how to add a route to send events.

  2. Na página Adicionar uma rota que é aberta, escolha os seguintes valores:

    • Nome: Escolha um nome para a sua rota.
    • Ponto de extremidade: escolha o ponto de extremidade dos Hubs de Eventos que você criou anteriormente na lista suspensa.
    • Fonte de dados: escolha Eventos do ciclo de vida do dispositivo.
    • Consulta de roteamento: digite opType='deleteDeviceIdentity'. Essa consulta limita os eventos do ciclo de vida do dispositivo para enviar apenas os eventos de exclusão.
  3. Selecione Guardar.

    Screenshot of the Azure portal showing how to add a route to send lifecycle events.

Depois de passar por esse fluxo, tudo está pronto para aposentar os dispositivos de ponta a ponta.

Validar

Para acionar o processo de desativação, você precisa excluir manualmente o dispositivo do Hub IoT.

Você pode excluir manualmente o dispositivo do Hub IoT com um comando da CLI do Azure ou no portal do Azure. Siga as etapas abaixo para excluir o dispositivo no portal do Azure:

  1. Navegue até o hub IoT e escolha dispositivos IoT nas opções de menu à esquerda.
  2. Você verá um dispositivo com o ID de registro do dispositivo escolhido na primeira metade deste artigo. Também pode escolher qualquer outro dispositivo para eliminar, desde que tenha um gémeo nos Gêmeos Digitais do Azure para que possa verificar se o gémeo é automaticamente eliminado depois de o dispositivo ser eliminado.
  3. Selecione o dispositivo e escolha Excluir.

Screenshot of the Azure portal showing how to delete device twin from the IoT devices.

Pode levar alguns minutos para ver as alterações refletidas nos Gêmeos Digitais do Azure.

Use o seguinte comando da CLI dos Gêmeos Digitais do Azure para verificar se o gêmeo do dispositivo na instância dos Gêmeos Digitais do Azure foi excluído. Há um espaço reservado para o nome do host da instância (você também pode usar o nome amigável da instância com uma ligeira diminuição no desempenho) e um espaço reservado para a ID de registro do dispositivo.

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

Você deve ver que o gêmeo do dispositivo não pode mais ser encontrado na instância do Azure Digital Twins.

Screenshot of the Command window showing that the twin can't be found anymore.

Clean up resources (Limpar recursos)

Se você não precisar mais dos recursos criados neste artigo, siga estas etapas para excluí-los.

Usando o Azure Cloud Shell ou a CLI local do Azure, você pode excluir todos os recursos do Azure em um grupo de recursos com o comando az group delete . Este comando remove o grupo de recursos; a instância do Azure Digital Twins; o hub IoT e o registro do dispositivo hub; o tópico Grade de Eventos e assinaturas associadas; o namespace Hubs de Eventos e ambos os aplicativos do Azure Functions, incluindo recursos associados, como armazenamento.

Importante

A eliminação de um grupo de recursos é irreversível. O grupo de recursos e todos os recursos nele contidos são eliminados permanentemente. Confirme que não elimina acidentalmente o grupo de recursos ou recursos errados.

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

Em seguida, exclua a pasta de exemplo do projeto que você baixou da sua máquina local.

Próximos passos

Os gêmeos digitais criados para os dispositivos são armazenados como uma hierarquia simples nos Gêmeos Digitais do Azure, mas podem ser enriquecidos com informações de modelo e uma hierarquia de vários níveis para a organização. Para saber mais sobre esse conceito, leia:

Para obter mais informações sobre como usar solicitações HTTP com funções do Azure, consulte:

Você pode escrever lógica personalizada para fornecer automaticamente essas informações usando os dados de modelo e gráfico já armazenados nos Gêmeos Digitais do Azure. Para ler mais sobre como gerenciar, atualizar e recuperar informações do gráfico de gêmeos, consulte os seguintes guias de instruções: