Dela via


Hantera enheter automatiskt i Azure Digital Twins med hjälp av Device Provisioning Service (DPS)

I den här artikeln får du lära dig hur du integrerar Azure Digital Twins med Device Provisioning Service (DPS).

Lösningen som beskrivs i den här artikeln gör att du kan automatisera processen för att etablera och dra tillbaka IoT Hub-enheter i Azure Digital Twins med hjälp av Device Provisioning Service.

Mer information om etablerings- och borttagningsstegen och för att bättre förstå de allmänna enhetshanteringsstegen som är gemensamma för alla IoT-företagsprojekt finns i avsnittet Enhetslivscykel i IoT Hubs dokumentation om enhetshantering.

Förutsättningar

Innan du kan konfigurera etableringen måste du konfigurera följande resurser:

Det här exemplet använder också en enhetssimulator som inkluderar etablering med hjälp av device provisioning-tjänsten. Enhetssimulatorn finns här: Azure Digital Twins och IoT Hub Integration Sample. Hämta exempelprojektet på datorn genom att gå till GitHub-lagringsplatsen för exemplet, som du kan ladda ned som en .zip-fil genom att välja knappen Kod och Ladda ned ZIP.

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

Packa upp den nedladdade mappen.

Du behöver Node.js installerat på datorn. Enhetssimulatorn baseras på Node.js, version 10.0.x eller senare.

Lösningsarkitekturen

Den här lösningen innehåller steg för att etablera och dra tillbaka en enhet i Azure Digital Twins med hjälp av Device Provisioning Service.

För att allokera enheter i lösningen flödar data mellan en termostatenhet och DPS. Data flödar sedan från DPS till IoT Hub och till Azure Digital Twins via en Azure-funktion.

Om du vill dra tillbaka en enhet flödar data från en manuell enhetsborttagning till Azure Digital Twins via IoT Hub, Event Hubs och en Azure-funktion.

Bilden nedan illustrerar den här arkitekturen.

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

Den här artikeln är uppdelad i två avsnitt som var och en fokuserar på en del av den här fullständiga arkitekturen:

Automatisk avetablering av enhet med enhetsetableringstjänsten

I det här avsnittet kommer du att koppla Enhetsetableringstjänsten till Azure Digital Twins till automatisk avetablering av enheter via sökvägen nedan. Det här diagrammet är ett utdrag från den fullständiga arkitekturen som visades tidigare.

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

Här är en beskrivning av processflödet:

  1. Enheten kontaktar DPS-slutpunkten och skickar identifierande information för att bevisa sin identitet.
  2. DPS validerar enhetsidentiteten genom att verifiera registrerings-ID:t och nyckeln mot registreringslistan och anropar en Azure-funktion för att utföra allokeringen.
  3. Azure-funktionen skapar en ny tvilling i Azure Digital Twins för enheten. Tvillingen har samma namn som enhetens registrerings-ID.
  4. DPS registrerar enheten med en IoT-hubb och fyller i enhetens valda tvillingtillstånd.
  5. IoT-hubben returnerar information om enhets-ID och IoT Hub-anslutningsinformationen till enheten. Enheten kan nu ansluta till IoT-hubben.

I följande avsnitt beskrivs stegen för att konfigurera det här enhetsflödet för automatisk avetablering.

Skapa en enhetsetableringstjänst

När en ny enhet etableras med enhetsetableringstjänsten kan en ny tvilling för den enheten skapas i Azure Digital Twins med samma namn som registrerings-ID:t.

Skapa en enhetsetableringstjänstinstans som ska användas för att etablera IoT-enheter. Du kan antingen använda Azure CLI-anvisningarna nedan eller använda Azure-portalen genom att följa Konfigurera IoT Hub Device Provisioning Service med Azure-portalen.

Följande Azure CLI-kommando skapar en enhetsetableringstjänst. Du måste ange namnet på enhetsetableringstjänsten, resursgruppen och regionen. Om du vill se vilka regioner som stöder Device Provisioning Service kan du besöka Azure-produkter som är tillgängliga per region. Kommandot kan köras i Cloud Shell eller lokalt om du har Azure CLI installerat på datorn.

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

Lägga till en funktion som ska användas med Device Provisioning Service

I ditt funktionsappsprojekt som du skapade i avsnittet Förutsättningar skapar du en ny funktion som ska användas med Device Provisioning Service. Den här funktionen används av Enhetsetableringstjänsten i en anpassad allokeringsprincip för att etablera en ny enhet.

Gå till funktionsappprojektet på datorn och följ stegen nedan.

  1. Skapa först en ny funktion av typen HTTP-utlösare i funktionsappprojektet.

  2. Lägg till ett nytt NuGet-paket i projektet: Microsoft.Azure.Devices.Provisioning.Service. Du kan också behöva lägga till fler paket i projektet, om paketen som används i koden inte redan ingår i projektet.

  3. I den nyligen skapade funktionskodfilen klistrar du in följande kod, namnger funktionen DpsAdtAllocationFunc.cs och sparar filen.

    // 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. Publicera projektet med funktionen DpsAdtAllocationFunc.cs till en funktionsapp i Azure.

    Anvisningar om hur du publicerar funktionen med Visual Studio finns i Utveckla Azure Functions med Visual Studio. Anvisningar om hur du publicerar funktionen med Visual Studio Code finns i Skapa en C#-funktion i Azure med Hjälp av Visual Studio Code. Anvisningar om hur du publicerar funktionen med hjälp av Azure CLI finns i Skapa en C#-funktion i Azure från kommandoraden.

Viktigt!

När du skapar funktionsappen för första gången i avsnittet Krav kan du redan ha tilldelat funktionen en åtkomstroll och konfigurerat programinställningarna för att den ska få åtkomst till din Azure Digital Twins-instans. Dessa måste göras en gång för hela funktionsappen, så kontrollera att de har slutförts i din app innan du fortsätter. Du hittar instruktioner i avsnittet Konfigurera publicerad app i artikeln Skriv appautentiseringskod.

Skapa enhetsetableringsregistrering

Därefter måste du skapa en registrering i Device Provisioning Service med hjälp av en anpassad allokeringsfunktion. Om du vill skapa en registrering följer du anvisningarna i avsnittet Skapa registrering i artikeln om anpassade allokeringsprinciper i dokumentationen för Enhetsetableringstjänsten.

När du går igenom det flödet måste du välja följande alternativ för att länka registreringen till den funktion som du skapade.

  • Välj hur du vill tilldela enheter till hubbar: Anpassad (Använd Azure-funktion).
  • Välj de IoT-hubbar som den här gruppen kan tilldelas: Välj ditt IoT-hubbnamn eller välj knappen Länka en ny IoT-hubb och välj din IoT-hubb bland alternativen.

Välj sedan knappen Välj en ny funktion för att länka funktionsappen till registreringsgruppen. Fyll sedan i följande värden:

  • Prenumeration: Din Azure-prenumeration fylls i automatiskt. Kontrollera att det är rätt prenumeration.
  • Funktionsapp: Välj funktionsappens namn.
  • Funktion: Välj DpsAdtAllocationFunc.

Spara dina uppgifter.

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

När du har skapat registreringen väljer du den för att visa dess inställningar. Kopiera primärnyckeln för registreringen, som kommer att användas senare i den här artikeln för att konfigurera enhetssimulatorn.

Konfigurera enhetssimulatorn

Det här exemplet använder en enhetssimulator som inkluderar etablering med hjälp av Device Provisioning Service. Enhetssimulatorn finns i Azure Digital Twins- och IoT Hub-integreringsexemplet som du laddade ned i avsnittet Förutsättningar.

Ladda upp modellen

Enhetssimulatorn är en termostattyp som använder modellen med följande ID: dtmi:contosocom:DigitalTwins:Thermostat;1. Du måste ladda upp den här modellen till Azure Digital Twins innan du kan skapa en tvilling av den här typen för enheten.

Modellen ser ut så här:

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

Om du vill ladda upp den här modellen till din twins-instans kör du följande Azure CLI-kommando, som laddar upp modellen ovan som infogad JSON. Du kan köra kommandot i Azure Cloud Shell i webbläsaren (använd Bash-miljön) eller på datorn om du har CLI installerat lokalt. Det finns en platshållare för instansens värdnamn (du kan också använda instansens eget namn med en liten minskning av prestanda).

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"    }  ]}' 

Kommentar

Om du använder något annat än Cloud Shell i Bash-miljön kan du behöva undvika vissa tecken i infogad JSON så att den parsas korrekt. Mer information finns i Använda specialtecken i olika gränssnitt.

Mer information om modeller finns i Hantera modeller.

Konfigurera och köra simulatorn

I ett kommandofönster på den lokala datorn går du till det nedladdade exemplet Azure Digital Twins och IoT Hub-integrering som du har packat upp tidigare och sedan till katalogen device-simulator . Installera sedan beroendena för projektet med hjälp av följande kommando:

npm install

I enhetssimulatorkatalogen kopierar du sedan .env.template-filen till en ny fil med namnet .env och samlar in följande värden för att fylla i inställningarna:

  • PROVISIONING_IDSCOPE: Om du vill hämta det här värdet går du till enhetsetableringstjänsten i Azure-portalen och väljer sedan Översikt i menyalternativen och letar efter fältets ID-omfång.

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

  • PROVISIONING_REGISTRATION_ID: Du kan välja ett registrerings-ID för din enhet.

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

  • PROVISIONING_SYMMETRIC_KEY: Den här miljövariabeln är den primära nyckeln för den registrering som du konfigurerade tidigare. Om du vill hämta det här värdet igen navigerar du till enhetsetableringstjänsten i Azure-portalen, väljer Hantera registreringar och väljer sedan den registreringsgrupp som du skapade tidigare och kopierar primärnyckeln.

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

Använd nu värdena ovan för att uppdatera filinställningarna för .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>"

Spara och stäng filen.

Börja köra enhetssimulatorn

Starta enhetssimulatorn med följande kommando i katalogen device-simulator i kommandofönstret:

node .\adt_custom_register.js

Du bör se att enheten registreras och ansluts till IoT Hub och sedan börjar skicka meddelanden. Screenshot of the Command window showing device registration and sending messages.

Validera

Flödet som du har konfigurerat i den här artikeln resulterar i att enheten registreras automatiskt i Azure Digital Twins. Använd följande Azure Digital Twins CLI-kommando för att hitta enhetens tvilling i Azure Digital Twins-instansen som du skapade. Det finns en platshållare för instansens värdnamn (du kan också använda instansens eget namn med en liten minskning av prestanda) och en platshållare för enhetsregistrerings-ID:t.

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

Du bör se tvillingen för enheten som hittas i Azure Digital Twins-instansen. Screenshot of the Command window showing newly created twin.

Autoretire-enhet med IoT Hub-livscykelhändelser

I det här avsnittet kommer du att koppla IoT Hub-livscykelhändelser till Azure Digital Twins till autoretire-enheter via sökvägen nedan. Det här diagrammet är ett utdrag från den fullständiga arkitekturen som visades tidigare.

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

Här är en beskrivning av processflödet:

  1. En extern eller manuell process utlöser borttagningen av en enhet i IoT Hub.
  2. IoT Hub tar bort enheten och genererar en livscykelhändelse för enheten som ska dirigeras till en händelsehubb.
  3. En Azure-funktion tar bort enhetens tvilling i Azure Digital Twins.

Följande avsnitt går igenom stegen för att konfigurera det här autoretire-enhetsflödet.

Skapa en händelsehubb

Därefter skapar du en Azure-händelsehubb för att ta emot IoT Hub-livscykelhändelser.

Följ stegen som beskrivs i snabbstarten Skapa en händelsehubb . Ge händelsehubben namnet lifecycleevents. Du använder det här händelsehubbens namn när du konfigurerar IoT Hub-vägen och en Azure-funktion i nästa avsnitt.

Skärmbilden nedan illustrerar skapandet av händelsehubben. Screenshot of the Azure portal window showing how to create an event hub with the name lifecycleevents.

Skapa SAS-princip för din händelsehubb

Därefter måste du skapa en SAS-princip (signatur för delad åtkomst) för att konfigurera händelsehubben med din funktionsapp. Så här skapar du SAS-principen:

  1. Gå till den händelsehubb som du skapade i Azure-portalen och välj Principer för delad åtkomst i menyalternativen till vänster.
  2. Markera Lägga till. I fönstret Lägg till SAS-princip som öppnas anger du ett valfritt principnamn och markerar kryssrutan Lyssna .
  3. Välj Skapa.

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

Konfigurera händelsehubb med funktionsapp

Konfigurera sedan den Azure-funktionsapp som du konfigurerade i avsnittet Förutsättningar så att den fungerar med din nya händelsehubb. Du konfigurerar funktionen genom att ange en miljövariabel i funktionsappen med händelsehubbens anslutningssträng.

  1. Öppna principen som du skapade och kopiera värdet Anslut ion string-primary key.

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

  2. Lägg till anslutningssträng som en variabel i funktionsappens inställningar med följande Azure CLI-kommando. Kommandot kan köras i Cloud Shell eller lokalt om du har Azure CLI installerat på datorn.

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

Lägga till en funktion för att dra tillbaka med livscykelhändelser för IoT Hub

I ditt funktionsappsprojekt som du skapade i avsnittet Krav skapar du en ny funktion för att dra tillbaka en befintlig enhet med IoT Hub-livscykelhändelser.

Mer information om livscykelhändelser finns i IoT Hub Icke-telemetrihändelser. Mer information om hur du använder Event Hubs med Azure-funktioner finns i Azure Event Hubs-utlösare för Azure Functions.

Gå till funktionsappprojektet på datorn och följ stegen nedan.

  1. Skapa först en ny funktion av typen Händelsehubbutlösare i funktionsappprojektet.

  2. Lägg till ett nytt NuGet-paket i projektet: Microsoft.Azure.Devices.Provisioning.Service. Du kan också behöva lägga till fler paket i projektet, om paketen som används i koden inte redan ingår i projektet.

  3. I den nyligen skapade funktionskodfilen klistrar du in följande kod, namnger funktionen DeleteDeviceInTwinFunc.cs och sparar filen.

    // 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. Publicera projektet med funktionen DeleteDeviceInTwinFunc.cs till en funktionsapp i Azure.

    Anvisningar om hur du publicerar funktionen med Visual Studio finns i Utveckla Azure Functions med Visual Studio. Anvisningar om hur du publicerar funktionen med Visual Studio Code finns i Skapa en C#-funktion i Azure med Hjälp av Visual Studio Code. Anvisningar om hur du publicerar funktionen med hjälp av Azure CLI finns i Skapa en C#-funktion i Azure från kommandoraden.

Viktigt!

När du skapar funktionsappen för första gången i avsnittet Krav kan du redan ha tilldelat funktionen en åtkomstroll och konfigurerat programinställningarna för att den ska få åtkomst till din Azure Digital Twins-instans. Dessa måste göras en gång för hela funktionsappen, så kontrollera att de har slutförts i din app innan du fortsätter. Du hittar instruktioner i avsnittet Konfigurera publicerad app i artikeln Skriv appautentiseringskod.

Skapa en IoT Hub-väg för livscykelhändelser

Nu ska du konfigurera en IoT Hub-väg för att dirigera enhetens livscykelhändelser. I det här fallet lyssnar du specifikt på enhetsborttagningshändelser som identifieras av if (opType == "deleteDeviceIdentity"). Den här händelsen utlöser borttagningen av det digitala tvillingobjektet, vilket slutför tillbakadragningsprocessen för en enhet och dess digitala tvilling.

Först måste du skapa en händelsehubbslutpunkt i din IoT-hubb. Sedan lägger du till en väg i IoT Hub för att skicka livscykelhändelser till den här händelsehubbens slutpunkt. Följ dessa steg för att skapa en händelsehubbslutpunkt:

  1. I Azure-portalen navigerar du till den IoT-hubb som du skapade i avsnittet Förutsättningar och väljer Meddelanderoutning i menyalternativen till vänster.

  2. Välj fliken Anpassade slutpunkter .

  3. Välj + Lägg till och välj Händelsehubbar för att lägga till en händelsehubbtypslutpunkt.

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

  4. I fönstret Lägg till en händelsehubbslutpunkt som öppnas väljer du följande värden:

    • Slutpunktsnamn: Välj ett slutpunktsnamn.
    • Namnområde för händelsehubben: Välj händelsehubbens namnområde i listrutan.
    • Händelsehubbinstans: Välj det händelsehubbnamn som du skapade i föregående steg.
  5. Välj Skapa. Håll det här fönstret öppet för att lägga till en väg i nästa steg.

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

Därefter lägger du till en väg som ansluter till slutpunkten som du skapade i ovanstående steg, med en routningsfråga som skickar borttagningshändelserna. Följ dessa steg för att skapa en väg:

  1. Gå till fliken Vägar och välj Lägg till för att lägga till en väg.

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

  2. På sidan Lägg till en väg som öppnas väljer du följande värden:

    • Namn: Välj ett namn för din väg.
    • Slutpunkt: Välj den Event Hubs-slutpunkt som du skapade tidigare i listrutan.
    • Datakälla: Välj Enhetslivscykelhändelser.
    • Routningsfråga: Ange opType='deleteDeviceIdentity'. Den här frågan begränsar enhetens livscykelhändelser till att endast skicka borttagningshändelserna.
  3. Välj Spara.

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

När du har gått igenom det här flödet är allt inställt på att dra tillbaka enheter från slutpunkt till slutpunkt.

Validera

För att utlösa processen för tillbakadragning måste du ta bort enheten manuellt från IoT Hub.

Du kan ta bort enheten manuellt från IoT Hub med ett Azure CLI-kommando eller i Azure-portalen. Följ stegen nedan för att ta bort enheten i Azure-portalen:

  1. Navigera till din IoT-hubb och välj IoT-enheter i menyalternativen till vänster.
  2. Du ser en enhet med det enhetsregistrerings-ID som du valde under den första halvan av den här artikeln. Du kan också välja vilken annan enhet som helst att ta bort, så länge den har en tvilling i Azure Digital Twins så att du kan kontrollera att tvillingen tas bort automatiskt när enheten har tagits bort.
  3. Välj enheten och välj Ta bort.

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

Det kan ta några minuter att se ändringarna återspeglas i Azure Digital Twins.

Använd följande Azure Digital Twins CLI-kommando för att verifiera att enhetens tvilling i Azure Digital Twins-instansen har tagits bort. Det finns en platshållare för instansens värdnamn (du kan också använda instansens eget namn med en liten minskning av prestanda) och en platshållare för enhetsregistrerings-ID:t.

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

Du bör se att enhetens tvilling inte längre kan hittas i Azure Digital Twins-instansen.

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

Rensa resurser

Om du inte längre behöver de resurser som skapats i den här artikeln följer du de här stegen för att ta bort dem.

Med Azure Cloud Shell eller lokala Azure CLI kan du ta bort alla Azure-resurser i en resursgrupp med kommandot az group delete . Det här kommandot tar bort resursgruppen. Azure Digital Twins-instansen. IoT-hubben och hubbens enhetsregistrering. Event Grid-ämnet och tillhörande prenumerationer. Event Hubs-namnområdet och båda Azure Functions-apparna, inklusive associerade resurser som lagring.

Viktigt!

Att ta bort en resursgrupp kan inte ångras. Resursgruppen och alla resurser som ingår i den tas bort permanent. Kontrollera att du inte av misstag tar bort fel resursgrupp eller resurser.

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

Ta sedan bort den projektexempelmapp som du laddade ned från den lokala datorn.

Nästa steg

De digitala tvillingar som skapas för enheterna lagras som en platt hierarki i Azure Digital Twins, men de kan berikas med modellinformation och en hierarki på flera nivåer för organisationen. Mer information om det här konceptet finns i:

Mer information om hur du använder HTTP-begäranden med Azure-funktioner finns i:

Du kan skriva anpassad logik för att automatiskt ange den här informationen med hjälp av modell- och grafdata som redan lagras i Azure Digital Twins. Mer information om hur du hanterar, uppgraderar och hämtar information från tvillingdiagrammet finns i följande instruktionsguider: