DPS(Device Provisioning Service)를 사용하여 Azure Digital Twins에서 디바이스 자동 관리
이 문서에서는 Azure Digital Twins를 DPS(Device Provisioning Service)와 통합하는 방법에 대해 알아봅니다.
이 문서에서 설명하는 솔루션을 통해 Device Provisioning Service를 사용하여 Azure Digital Twins에서 IoT Hub 디바이스를 프로비전하고 사용 중지하는 프로세스를 자동화할 수 있습니다.
프로비전 및 사용 중지 단계에 대한 자세한 내용 및 모든 엔터프라이즈 IoT 프로젝트에 공통적인 일반 디바이스 관리 단계를 보다 잘 이해하려면 IoT Hub의 디바이스 관리 설명서에서 디바이스 수명 주기 섹션을 참조하세요.
필수 조건
프로비저닝을 설정하려면 먼저 다음 리소스를 설정해야 합니다.
- Azure Digital Twins 인스턴스. 인스턴스 및 인증 설정의 지침에 따라 Azure Digital Twins 인스턴스를 만듭니다. Azure Portal(지침)에서 인스턴스의 호스트 이름을 수집합니다.
- IoT 허브. 지침은 IoT Hub 빠른 시작의 "IoT Hub 만들기" 섹션을 참조하세요.
- IoT Hub 데이터를 기반으로 디지털 트윈 정보를 업데이트하는 Azure 함수. IoT 허브 데이터 수집의 지침에 따라 이 Azure 함수를 만듭니다. 이 문서에서 사용할 함수 이름을 수집합니다.
또한 이 샘플에서는 Device Provisioning Service를 사용한 프로비저닝을 포함하는 디바이스 시뮬레이터를 사용합니다. 디바이스 시뮬레이터는 Azure Digital Twins 및 IoT Hub 통합 샘플에 있습니다. 샘플에 대한 GitHub 리포지토리로 이동하여 컴퓨터에서 샘플 프로젝트를 가져옵니다. 그러면 코드 단추를 선택하고 ZIP을 다운로드하여 .zip 파일로 다운로드할 수 있습니다.
다운로드한 폴더의 압축을 풉니다.
컴퓨터에 Node.js가 설치되어 있어야 합니다. 디바이스 시뮬레이터는 Node.js, 버전 10.0.x 이상을 기반으로 합니다.
솔루션 아키텍처
이 솔루션에는 Device Provisioning Service를 사용하여 Azure Digital Twins에서 디바이스를 프로비전하고 사용 중지하는 단계가 포함됩니다.
솔루션에 디바이스를 할당하기 위해 자동 온도 조절 디바이스와 DPS 간에 데이터가 전달됩니다. 그런 다음, 데이터는 Azure 함수를 통해 DPS에서 IoT Hub 및 Azure Digital Twins로 전달됩니다.
디바이스를 사용 중지하기 위해 수동 디바이스 삭제의 데이터는 IoT Hub, Event Hubs 및 Azure 함수를 통해 Azure Digital Twins로 전달됩니다.
아래 이미지는 이 아키텍처를 보여줍니다.
이 문서는 이러한 전체 아키텍처의 한 부분에 중점을 두는 두 개의 섹션으로 구분되어 있습니다.
Device Provisioning Service를 사용하여 디바이스 자동 프로비전
이 섹션에서는 Device Provisioning Service를 Azure Digital Twins에 연결하여 아래 경로를 통해 디바이스를 자동으로 프로비전합니다. 이 다이어그램은 앞에 표시된 전체 아키텍처에서 발췌한 것입니다.
다음은 프로세스 흐름에 대한 설명입니다.
- 디바이스는 DPS 엔드포인트에 연결하고 식별 정보를 전달하여 ID를 증명합니다.
- DPS는 등록 목록에 대해 등록 ID 및 키의 유효성을 검사하여 디바이스 ID의 유효성을 검사하고 Azure 함수를 호출하여 할당을 수행합니다.
- Azure 함수는 Azure Digital Twins에 디바이스에 대한 새 트윈을 만듭니다. 트윈은 디바이스의 등록 ID와 동일한 이름을 갖습니다.
- DPS는 디바이스를 IoT 허브에 등록하고 디바이스의 선택된 트윈 상태를 채웁니다.
- IoT 허브는 디바이스 ID 정보 및 IoT 허브 연결 정보를 디바이스에 반환합니다. 이제 디바이스에서 IoT 허브에 연결할 수 있습니다.
다음 섹션에서는 이 자동 프로비전 디바이스 흐름을 설정하는 단계를 안내합니다.
Device Provisioning Service 만들기
Device Provisioning Service를 사용하여 새 디바이스를 프로비저닝하는 경우 등록 ID와 동일한 이름을 사용하여 Azure Digital Twins에서 해당 디바이스에 대한 새 트윈을 만들 수 있습니다.
IoT 디바이스를 프로비저닝하는 데 사용되는 Device Provisioning Service 인스턴스를 만듭니다. 아래의 Azure CLI 지침을 사용하거나 Azure Portal에서 IoT Hub Device Provisioning Service 설정에 따라 Azure Portal을 사용할 수 있습니다.
다음 Azure CLI 명령은 Device Provisioning Service를 만듭니다. Device Provisioning Service 이름, 리소스 그룹 및 지역을 지정해야 합니다. Device Provisioning Service를 지원하는 지역을 확인하려면 지역별 사용 가능한 Azure 제품을 방문하세요. Azure CLI가 머신에 설치되어 있는 경우 이 명령은 Cloud Shell 또는 로컬로 실행할 수 있습니다.
az iot dps create --name <Device-Provisioning-Service-name> --resource-group <resource-group-name> --location <region>
Device Provisioning Service에서 사용할 함수 추가
필수 조건 섹션에서 만든 함수 앱 프로젝트 내에서 Device Provisioning Service에 사용할 새 함수를 만듭니다. 이 함수는 사용자 지정 할당 정책의 Device Provisioning Service에서 새 디바이스를 프로비저닝하는 데 사용됩니다.
컴퓨터에서 함수 앱 프로젝트로 이동하고 아래 단계를 따릅니다.
먼저 함수 앱 프로젝트에서 HTTP-trigger 형식의 새 함수를 만듭니다.
프로젝트에 새 NuGet 패키지를 추가합니다. Microsoft.Azure.Devices.Provisioning.Service. 코드에 사용된 패키지가 프로젝트에 아직 포함되지 않은 경우 프로젝트에 더 많은 패키지를 추가해야 할 수도 있습니다.
새로 만들어진 함수 코드 파일에 다음 코드를 붙여넣고 함수 이름을 DpsAdtAllocationFunc.cs로 지정하고 파일을 저장합니다.
// 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; } } }
DpsAdtAllocationFunc.cs 함수를 사용하여 프로젝트를 Azure의 함수 앱에 게시합니다.
Visual Studio를 사용하여 함수를 게시하는 방법에 대한 지침은 Visual Studio를 사용하여 Azure Functions 개발을 참조하세요. Visual Studio Code를 사용하여 함수를 게시하는 방법에 대한 지침은 Visual Studio Code를 사용하여 Azure에서 C# 함수 만들기를 참조하세요. Azure CLI를 사용하여 함수를 게시하는 방법에 대한 지침은 명령줄에서 Azure의 C# 함수 만들기를 참조하세요.
Important
필수 조건 섹션에서 함수 앱을 처음 만들 때 이미 함수의 액세스 역할을 할당하고 Azure Digital Twins 인스턴스에 액세스하도록 애플리케이션 설정을 구성했을 수 있습니다. 이 작업은 전체 함수 앱에 대해 한 번만 수행해야 하므로 계속하기 전에 앱에서 작업이 완료되었는지 확인합니다. ‘앱 인증 코드 쓰기’ 문서의 게시된 앱 구성 섹션에서 지침을 찾을 수 있습니다.
Device Provisioning 등록 만들기
다음으로 사용자 지정 할당 함수를 사용하여 Device Provisioning Service에서 등록을 만들어야 합니다. 등록을 만들려면 Device Provisioning Service 설명서에서 사용자 지정 할당 정책 문서의 등록 만들기 섹션에 있는 지침에 따라 작업을 수행합니다.
이 흐름을 진행하는 동안 다음 옵션을 선택하여 만든 함수에 등록을 연결해야 합니다.
- 허브에 디바이스를 할당할 방법 선택: 사용자 지정(Azure 함수 사용)
- 이 그룹을 할당할 수 있는 IoT 허브 선택: IoT 허브 이름을 선택하거나 새 IoT 허브 연결 단추를 선택하고 옵션에서 IoT 허브를 선택합니다.
그런 다음 새 함수 선택 단추를 선택하여 함수 앱을 등록 그룹에 연결합니다. 그 후, 다음 값을 채웁니다.
- 구독: Azure 구독이 자동으로 채워집니다. 올바른 구독인지 확인합니다.
- 함수 앱: 함수 앱 이름을 선택합니다.
- 함수: DpsAdtAllocationFunc 함수를 선택합니다.
세부 정보를 저장합니다.
등록을 만든 후 해당 설정을 보려면 등록을 선택합니다. 등록에 대한 기본 키를 복사합니다. 이 키는 나중에 이 문서에서 디바이스 시뮬레이터를 구성하는 데 사용됩니다.
디바이스 시뮬레이터 설정
이 샘플에서는 Device Provisioning Service를 사용한 프로비저닝을 포함하는 디바이스 시뮬레이터를 사용합니다. 디바이스 시뮬레이터는 필수 조건 섹션에서 다운로드한 Azure Digital Twins 및 IoT Hub 통합 샘플에 있습니다.
모델 업로드
디바이스 시뮬레이터는 이 ID: dtmi:contosocom:DigitalTwins:Thermostat;1
의 모델을 사용하는 자동 온도 조절기 형식 디바이스입니다. 디바이스에 대해 이 형식의 트윈을 만들려면 먼저 이 모델을 Azure Digital Twins에 업로드해야 합니다.
모델은 다음과 같습니다.
{
"@id": "dtmi:contosocom:DigitalTwins:Thermostat;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;3",
"contents": [
{
"@type": "Property",
"name": "Temperature",
"schema": "double"
}
]
}
이 모델을 Twins 인스턴스에 업로드하려면 위 모델을 인라인 JSON으로 업로드하는 다음 Azure CLI 명령을 실행합니다. 브라우저의 Azure Cloud Shell(Bash 환경 사용)에서 또는 CLI가 로컬로 설치된 경우 머신에서 명령을 실행할 수 있습니다. 인스턴스의 호스트 이름에 대한 하나의 자리 표시자가 있습니다(성능이 약간 저하된 인스턴스의 식별 이름을 사용할 수도 있음).
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" } ]}'
참고 항목
Bash 환경에서 Cloud Shell 이외의 것을 사용하는 경우 올바르게 구문 분석되도록 인라인 JSON에서 특정 문자를 이스케이프 처리해야 할 수 있습니다. 자세한 내용은 다른 셸에서 특수 문자 사용을 참조하세요.
모델에 대한 자세한 내용은 모델 관리를 참조하세요.
시뮬레이터 구성 및 실행
로컬 컴퓨터의 명령 창에서 이전에 압축을 푼 다운로드한 샘플 Azure Digital Twins 및 IoT Hub 통합으로 이동한 다음 device-simulator 디렉터리로 이동합니다. 다음으로 다음 명령을 사용하여 프로젝트에 대한 종속성을 설치합니다.
npm install
그런 다음, 디바이스 시뮬레이터 디렉터리에서 .env.template 파일을 .env라는 새 파일에 복사하고 다음 값을 수집하여 설정을 채웁니다.
PROVISIONING_IDSCOPE: 이 값을 얻으려면 Azure Portal에서 Device Provisioning Service로 이동한 다음 메뉴 옵션에서 개요를 선택하고 필드 ID 범위를 찾습니다.
PROVISIONING_REGISTRATION_ID: 디바이스에 대한 등록 ID를 선택할 수 있습니다.
ADT_MODEL_ID:
dtmi:contosocom:DigitalTwins:Thermostat;1
PROVISIONING_SYMMETRIC_KEY: 이 환경 변수는 이전에 설정한 등록의 기본 키입니다. 이 값을 다시 얻으려면 Azure Portal에서 Device Provisioning Service로 이동하고 등록 관리를 선택한 다음 이전에 만든 등록 그룹을 선택하고 기본 키를 복사합니다.
이제 위의 값을 사용하여 .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>"
파일을 저장 후 닫습니다.
디바이스 시뮬레이터 실행 시작
명령 창의 device-simulator 디렉터리에서 다음 명령을 사용하여 디바이스 시뮬레이터를 시작합니다.
node .\adt_custom_register.js
디바이스를 등록하고 IoT Hub에 연결한 다음 메시지 보내기를 시작해야 합니다.
유효성 검사
이 문서에서 설정한 흐름의 결과로 디바이스가 Azure Digital Twins에 자동으로 등록됩니다. 다음 Azure Digital Twins CLI 명령을 사용하여 사용자가 만든 Azure Digital Twins 인스턴스에서 디바이스 트윈을 찾습니다. 인스턴스의 호스트 식별 이름에 대한 자리 표시자(성능이 약간 저하된 인스턴스의 식별 이름을 사용할 수도 있음)와 디바이스 등록 ID에 대한 자리 표시자가 있습니다.
az dt twin show --dt-name <instance-hostname-or-name> --twin-id "<device-registration-ID>"
Azure Digital Twins 인스턴스에서 발견되는 디바이스 트윈이 표시되어야 합니다.
IoT Hub 수명 주기 이벤트를 사용하여 디바이스 자동 만료
이 섹션에서는 Azure Digital Twins에 IoT Hub 수명 주기 이벤트를 연결하여 아래 경로를 통해 디바이스를 자동 중지합니다. 이 다이어그램은 앞에 표시된 전체 아키텍처에서 발췌한 것입니다.
다음은 프로세스 흐름에 대한 설명입니다.
- 외부 또는 수동 프로세스는 IoT Hub에서 디바이스 삭제를 트리거합니다.
- IoT Hub는 디바이스를 삭제하고 이벤트 허브로 라우팅되는 디바이스 수명 주기 이벤트를 생성합니다.
- Azure 함수는 Azure Digital Twins에서 디바이스 트윈을 삭제합니다.
다음 섹션에서는 이 자동 중지 디바이스 흐름을 설정하는 단계를 안내합니다.
이벤트 허브 만들기
다음으로 IoT Hub 수명 주기 이벤트를 수신하는 Azure 이벤트 허브를 만듭니다.
이벤트 허브 만들기 빠른 시작에 설명된 단계를 따릅니다. 이벤트 허브 이름을 lifecycleevents로 지정합니다. 다음 섹션에서 IoT Hub 경로 및 Azure 함수를 설정할 때 이 이벤트 허브 이름을 사용합니다.
이벤트 허브에 대한 SAS 정책 만들기
다음으로 SAS(공유 액세스 서명) 정책을 만들어 함수 앱을 사용하여 이벤트 허브를 구성해야 합니다. SAS 정책 만들기:
- Azure Portal에서 만든 이벤트 허브로 이동하고 왼쪽의 메뉴 옵션에서 공유 액세스 정책을 선택합니다.
- 추가를 선택합니다. SAS 정책 추가 창이 열리면 원하는 정책 이름을 입력하고 수신 대기 확인란을 선택합니다.
- 만들기를 실행합니다.
함수 앱을 사용하여 이벤트 허브 구성
다음으로 필수 조건 섹션에서 설정한 Azure 함수 앱을 구성하여 새 이벤트 허브를 사용합니다. 함수를 구성하려면 이벤트 허브의 연결 문자열을 사용하여 함수 앱 내에 환경 변수를 설정합니다.
방금 만든 정책을 열고 연결 문자열-기본 키 값을 복사합니다.
다음 Azure CLI 명령을 사용하여 함수 앱 설정에서 연결 문자열을 변수로 추가합니다. Azure CLI가 머신에 설치되어 있는 경우 이 명령은 Cloud Shell 또는 로컬로 실행할 수 있습니다.
az functionapp config appsettings set --settings "EVENTHUB_CONNECTIONSTRING=<Event-Hubs-SAS-connection-string-Listen>" --resource-group <resource-group> --name <your-function-app-name>
IoT Hub 수명 주기 이벤트를 사용하여 사용 중지하는 함수 추가
필수 조건 섹션에서 만든 함수 앱 프로젝트 내에서 IoT Hub 수명 주기 이벤트를 사용하여 기존 디바이스를 사용 중지하는 새 함수를 만듭니다.
수명 주기 이벤트에 대한 자세한 내용은 IoT Hub 비-원격 분석 이벤트를 참조하세요. Azure Functions와 함께 Event Hubs를 사용하는 방법에 대한 자세한 내용은 Azure Functions에 대한 Azure Event Hubs 트리거를 참조하세요.
컴퓨터에서 함수 앱 프로젝트로 이동하고 아래 단계를 따릅니다.
먼저 함수 앱 프로젝트에서 이벤트 허브 Trigger 형식의 새 함수를 만듭니다.
프로젝트에 새 NuGet 패키지를 추가합니다. Microsoft.Azure.Devices.Provisioning.Service. 코드에 사용된 패키지가 프로젝트에 아직 포함되지 않은 경우 프로젝트에 더 많은 패키지를 추가해야 할 수도 있습니다.
새로 만들어진 함수 코드 파일에 다음 코드를 붙여넣고 함수 이름을 DeleteDeviceInTwinFunc.cs로 지정하고 파일을 저장합니다.
// 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"); } } } }
DeleteDeviceInTwinFunc.cs 함수가 있는 프로젝트를 Azure의 함수 앱에 게시합니다.
Visual Studio를 사용하여 함수를 게시하는 방법에 대한 지침은 Visual Studio를 사용하여 Azure Functions 개발을 참조하세요. Visual Studio Code를 사용하여 함수를 게시하는 방법에 대한 지침은 Visual Studio Code를 사용하여 Azure에서 C# 함수 만들기를 참조하세요. Azure CLI를 사용하여 함수를 게시하는 방법에 대한 지침은 명령줄에서 Azure의 C# 함수 만들기를 참조하세요.
Important
필수 조건 섹션에서 함수 앱을 처음 만들 때 이미 함수의 액세스 역할을 할당하고 Azure Digital Twins 인스턴스에 액세스하도록 애플리케이션 설정을 구성했을 수 있습니다. 이 작업은 전체 함수 앱에 대해 한 번만 수행해야 하므로 계속하기 전에 앱에서 작업이 완료되었는지 확인합니다. ‘앱 인증 코드 쓰기’ 문서의 게시된 앱 구성 섹션에서 지침을 찾을 수 있습니다.
수명 주기 이벤트에 대한 IoT Hub 경로 만들기
이제 디바이스 수명 주기 이벤트를 라우팅하기 위해 IoT Hub 경로를 설정합니다. 이 경우에는 if (opType == "deleteDeviceIdentity")
에 의해 식별되는 디바이스 삭제 이벤트를 특별히 수신 대기합니다. 이 이벤트는 디지털 트윈 항목의 삭제를 트리거하고 디바이스와 디지털 트윈의 사용 중지 프로세스를 완료합니다.
먼저 IoT 허브에서 이벤트 허브 엔드포인트를 만들어야 합니다. 그런 다음 IoT 허브의 경로를 추가하여 이 이벤트 허브 엔드포인트에 수명 주기 이벤트를 보냅니다. 이벤트 허브 엔드포인트를 만들려면 다음 단계를 수행합니다.
Azure Portal의 필수 조건 섹션에서 만든 IoT 허브로 이동하고 왼쪽의 메뉴 옵션에서 메시지 라우팅을 선택합니다.
사용자 지정 엔드포인트 탭을 선택합니다.
+ 추가를 선택하고 Event Hubs를 선택하여 이벤트 허브 형식 엔드포인트를 추가합니다.
이벤트 허브 엔드포인트 추가 창이 열리면 다음 값을 선택합니다.
- 엔드포인트 이름: 엔드포인트 이름을 선택합니다.
- 이벤트 허브 네임스페이스: 드롭다운 목록에서 이벤트 허브 네임스페이스를 선택합니다.
- 이벤트 허브 인스턴스: 이전 단계에서 만든 이벤트 허브 이름을 선택합니다.
만들기를 실행합니다. 다음 단계에서 경로를 추가하려면 이 창을 열어 둡니다.
다음으로, 삭제 이벤트를 보내는 라우팅 쿼리를 사용하여 위의 단계에서 만든 엔드포인트에 연결하는 경로를 추가합니다. 다음 단계에 따라 경로를 만듭니다.
경로 탭으로 이동하고 추가를 선택하여 경로를 추가합니다.
경로 추가 페이지가 열리면 다음 값을 선택합니다.
- 이름: 경로의 이름을 선택합니다.
- 엔드포인트: 드롭다운에서 이전에 만든 Event Hubs 엔드포인트를 선택합니다.
- 데이터 원본: 디바이스 수명 주기 이벤트를 선택합니다.
- 라우팅 쿼리:
opType='deleteDeviceIdentity'
를 입력합니다. 이 쿼리는 삭제 이벤트만 전송하도록 디바이스 수명 주기 이벤트를 제한합니다.
저장을 선택합니다.
이 흐름이 완료되면 디바이스 엔드투엔드 사용 중지가 설정된 것입니다.
유효성 검사
사용 중지 프로세스를 트리거하려면 IoT Hub에서 디바이스를 수동으로 삭제해야 합니다.
Azure CLI 명령을 사용하여 또는 Azure Portal에서 IoT Hub로부터 디바이스를 수동으로 삭제할 수 있습니다. Azure Portal에서 디바이스를 삭제하려면 다음 단계를 수행합니다.
- IoT 허브로 이동하고 왼쪽의 메뉴 옵션에서 IoT 디바이스를 선택합니다.
- 이 문서의 전반부에서 선택한 디바이스 등록 ID를 가진 디바이스가 표시됩니다. Azure Digital Twins에 트윈이 있는 한 다른 모든 디바이스는 선택하여 삭제할 수 있으므로, 디바이스를 삭제한 후 트윈이 자동으로 삭제되는지 확인할 수 있습니다.
- 디바이스를 선택하고 삭제를 선택합니다.
Azure Digital Twins에 반영된 변경 내용을 확인하는 데 몇 분 정도 걸릴 수 있습니다.
다음 Azure Digital Twins CLI 명령을 사용하여 Azure Digital Twins 인스턴스에서 디바이스 트윈이 삭제된 것을 확인합니다. 인스턴스의 호스트 식별 이름에 대한 자리 표시자(성능이 약간 저하된 인스턴스의 식별 이름을 사용할 수도 있음)와 디바이스 등록 ID에 대한 자리 표시자가 있습니다.
az dt twin show --dt-name <instance-hostname-or-name> --twin-id "<device-registration-ID>"
디바이스 트윈이 더 이상 Azure Digital Twins 인스턴스에서 찾을 수 없어야 합니다.
리소스 정리
이 문서에서 만든 리소스가 더 이상 필요하지 않으면 다음 단계에 따라 삭제합니다.
Azure Cloud Shell 또는 로컬 Azure CLI를 사용하면 az group delete 명령으로 리소스 그룹의 모든 Azure 리소스를 삭제할 수 있습니다. 이 명령을 사용하면 Azure Digital Twins 인스턴스, IoT 허브와 허브 디바이스 등록, 이벤트 그리드 토픽과 관련 구독, Event Hubs 네임스페이스 및 스토리지와 같은 관련 리소스를 포함한 두 Azure Functions 앱을 비롯한 리소스 그룹이 제거됩니다.
Important
리소스 그룹을 삭제하면 다시 되돌릴 수 없습니다. 리소스 그룹 및 그 안에 포함된 모든 리소스가 영구적으로 삭제됩니다. 잘못된 리소스 그룹 또는 리소스를 자동으로 삭제하지 않도록 해야 합니다.
az group delete --name <your-resource-group>
그런 다음 로컬 컴퓨터에서 다운로드한 프로젝트 샘플 폴더를 삭제합니다.
다음 단계
디바이스에 대해 생성된 디지털 트윈은 Azure Digital Twins에 플랫 계층으로 저장되지만 모델 정보 및 조직에 대한 다중 수준 계층 구조를 사용하여 보강할 수 있습니다. 이 개념에 대한 자세한 내용은 다음을 참조하세요.
Azure 함수에서 HTTP 요청을 사용하는 방법에 대한 자세한 내용은 다음을 참조하세요.
Azure Digital Twins에 이미 저장된 모델 및 그래프 데이터를 사용하여 이 정보를 자동으로 제공하는 사용자 지정 논리를 작성할 수 있습니다. 트윈 그래프에서 정보를 관리, 업그레이드, 검색하는 방법에 대한 자세한 내용은 다음 방법 가이드를 참조하세요.