디바이스 쌍 시작(Java)

디바이스 쌍은 메타데이터, 구성, 조건을 비롯한 디바이스 상태 정보를 저장하는 JSON 문서입니다. IoT Hub는 여기에 연결하는 각 디바이스에 대해 하나의 디바이스 쌍을 유지합니다.

참고 항목

이 문서에서 설명하는 기능은 IoT Hub의 표준 계층에서만 사용할 수 있습니다. 기본 및 표준/무료 IoT Hub 계층에 대한 자세한 내용은 솔루션에 적합한 IoT Hub 계층 선택을 참조하세요.

디바이스 쌍의 용도:

  • 솔루션 백 엔드의 디바이스 메타데이터를 저장합니다.

  • 디바이스 앱의 사용 가능한 기능 및 상태(예: 사용된 연결 방법)와 같은 현재 상태 정보를 보고합니다.

  • 디바이스 앱과 백 엔드 앱 간에 장기 실행 워크플로(예: 펌웨어 및 구성 업데이트)의 상태를 동기화합니다.

  • 디바이스 메타데이터, 구성 또는 상태를 쿼리합니다.

디바이스 쌍은 디바이스 구성 및 상태를 동기화하고 쿼리하기 위해 설계되었습니다. 디바이스 쌍을 사용하는 경우를 포함한 디바이스 쌍에 대한 자세한 내용은 디바이스 쌍 이해를 참조하세요.

IoT 허브는 다음 요소를 포함하는 디바이스 쌍을 저장합니다.

  • 태그. 솔루션 백 엔드만 액세스할 수 있는 디바이스 메타데이터입니다.

  • desired 속성. 솔루션 백 엔드에서 수정할 수 있고 디바이스 앱에서 관찰할 수 있는 JSON 개체입니다.

  • reported 속성. 디바이스 앱에서 수정할 수 있고 솔루션 백 엔드에서 읽을 수 있는 JSON 개체입니다.

태그 및 속성은 배열을 포함할 수 없지만 중첩된 개체를 포함할 수 있습니다.

다음 그림은 디바이스 쌍 조직을 보여 줍니다.

디바이스 쌍 개념 다이어그램의 스크린샷

또한 솔루션 백 엔드는 위의 모든 데이터를 기반으로 하는 디바이스 쌍을 쿼리할 수 있습니다. 디바이스 쌍에 대한 자세한 내용은 디바이스 쌍 이해를 참조하세요. 쿼리에 대한 자세한 내용은 IoT Hub 쿼리 언어를 참조하세요.

이 문서는 다음을 수행하는 방법을 보여줍니다.

  • 시뮬레이션된 디바이스 앱을 사용하여 해당 연결 채널을 디바이스 쌍의 reported 속성으로 보고합니다.

  • 이전에 만든 태그 및 속성에 필터를 사용하여 백 엔드 앱에서 디바이스를 쿼리합니다.

이 문서에서는 다음 두 개의 Java 콘솔 앱을 만듭니다.

  • add-tags-query: 태그를 추가하고 디바이스 쌍을 쿼리하는 백 엔드 앱입니다.
  • 시뮬레이션된 디바이스: IoT 허브에 연결하고 연결 상태를 보고하는 시뮬레이션된 디바이스 앱입니다.

참고 항목

디바이스 및 백 엔드 앱을 빌드하는 데 사용할 수 있는 SDK 도구에 대한 자세한 내용은 Azure IoT SDK를 참조하세요.

필수 조건

  • IoT 허브. CLI 또는 Azure Portal을 사용하여 만듭니다.

  • 등록된 디바이스. Azure Portal에 하나를 등록합니다.

  • Java SE Development Kit 8. JDK 8용 다운로드를 가져오려면 장기 지원에서 Java 8을 선택해야 합니다.

  • Maven 3

  • 방화벽에서 포트 8883이 열려 있는지 확인합니다. 이 문서의 디바이스 샘플은 포트 8883을 통해 통신하는 MQTT 프로토콜을 사용합니다. 이 포트는 일부 회사 및 교육용 네트워크 환경에서 차단될 수 있습니다. 이 문제를 해결하는 자세한 내용과 방법은 IoT Hub에 연결(MQTT)을 참조하세요.

IoT Hub 연결 문자열 가져오기

이 문서에서는 디바이스 쌍에 원하는 속성을 추가하고 ID 레지스트리를 쿼리하여 그에 따라 업데이트된 보고된 속성이 있는 모든 디바이스를 찾는 백 엔드 서비스를 만듭니다. 서비스는 디바이스 쌍의 원하는 속성을 수정하려면 서비스 연결 권한이 필요하며, ID 레지스트리를 쿼리하기 위한 레지스트리 읽기 권한이 필요합니다. 이러한 두 가지 권한만 포함하는 기본 공유 액세스 정책은 없으므로 만들어야 합니다.

서비스 연결레지스트리 읽기 권한을 부여하는 공유 액세스 정책을 만들고 이 정책에 대한 연결 문자열을 가져오려면 다음 단계를 수행합니다.

  1. Azure Portal에서 리소스 그룹을 선택합니다. 허브가 있는 리소스 그룹을 선택한 다음, 리소스 목록에서 허브를 선택합니다.

  2. 허브의 왼쪽 창에서 공유 액세스 정책을 선택합니다.

  3. 정책 목록 위의 상단 메뉴에서 공유 정책 액세스 정책 추가를 선택합니다.

  4. 오른쪽의 공유 액세스 정책 추가 창에서 정책에 사용할 설명형 이름(예: serviceAndRegistryRead)을 입력합니다. 권한에서 레지스트리 읽기서비스 연결을 선택한 다음 추가를 선택합니다.

    새 공유 액세스 정책을 추가하는 방법을 보여 주는 화면 캡처

  5. 정책 목록에서 새 정책을 선택합니다.

  6. 기본 연결 문자열의 복사 아이콘을 선택하고 값을 저장합니다.

    연결 문자열을 검색하는 방법을 보여 주는 화면 캡처.

IoT Hub 공유 액세스 정책 및 사용 권한에 대한 자세한 내용은 액세스 제어 및 권한을 참조하세요.

보고된 속성을 업데이트하는 디바이스 앱 만들기

이 섹션에서는 허브에 myDeviceId로 연결하는 Java 콘솔 앱을 만든 다음, 디바이스 쌍의 reported 속성을 업데이트하여 셀룰러 네트워크를 사용하여 연결되었는지 확인합니다.

  1. 명령 프롬프트에서 다음 명령을 사용하여 iot-java-twin-getstarted 폴더에 simulated-device라는 새 Maven 프로젝트를 만듭니다.

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=simulated-device -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. 명령 프롬프트에서 simulated-device 폴더로 이동합니다.

  3. 텍스트 편집기를 사용하여 simulated-device 폴더에서 pom.xml 파일을 열고 종속성 노드에 다음 종속성을 추가합니다. 이러한 종속성을 통해 IoT Hub와 통신하도록 앱에서 iot-device-client 패키지를 사용할 수 있습니다.

    <dependency>
      <groupId>com.microsoft.azure.sdk.iot</groupId>
      <artifactId>iot-device-client</artifactId>
      <version>1.17.5</version>
    </dependency>
    

    참고 항목

    Maven 검색을 사용하여 iot-device-client의 최신 버전을 확인할 수 있습니다.

  4. 종속성 노드에 다음 종속성을 추가합니다. 이 종속성은 디바이스 클라이언트 SDK에서 로깅을 구현하는 데 사용하는 Apache SLF4J 로깅 외관에 맞게 NOP를 구성합니다. 이 구성은 선택 사항이지만, 건너뛰면 앱을 실행할 때 콘솔에 경고가 표시될 수 있습니다. 디바이스 클라이언트 SDK에 로그인하는 방법에 대한 자세한 내용은 Java용 Azure IoT 디바이스 SDK 샘플 추가 정보 파일에서 로깅을 참조하세요.

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-nop</artifactId>
      <version>1.7.28</version>
    </dependency>
    
  5. 종속성 노드 뒤에 다음 빌드 노드를 추가합니다. 이 구성에서는 Maven에 Java 1.8을 사용하여 앱을 빌드하도록 지시합니다.

    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.3</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
          </configuration>
        </plugin>
      </plugins>
    </build>
    
  6. pom.xml 파일을 저장하고 닫습니다.

  7. 텍스트 편집기를 사용하여 simulated-device\src\main\java\com\mycompany\app\App.java 파일을 엽니다.

  8. 파일에 다음 import 문을 추가합니다.

    import com.microsoft.azure.sdk.iot.device.*;
    import com.microsoft.azure.sdk.iot.device.DeviceTwin.*;
    
    import java.io.IOException;
    import java.net.URISyntaxException;
    import java.util.Scanner;
    
  9. 다음 클래스 수준 변수를 App 클래스에 추가합니다. {yourdeviceconnectionstring}을 IoT Hub에 디바이스를 등록할 때 본 디바이스 연결 문자열로 바꿉니다.

    private static String connString = "{yourdeviceconnectionstring}";
    private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
    private static String deviceId = "myDeviceId";
    

    이 샘플 앱은 DeviceClient 개체를 인스턴스화할 때 프로토콜 변수를 사용합니다.

  10. 쌍 업데이트에 대한 정보를 인쇄하려면 App 클래스에 다음 메서드를 추가합니다.

    protected static class DeviceTwinStatusCallBack implements IotHubEventCallback {
        @Override
        public void execute(IotHubStatusCode status, Object context) {
          System.out.println("IoT Hub responded to device twin operation with status " + status.name());
        }
      }
    
  11. main 메서드의 코드를 다음 코드로 바꿉니다.

    • IoT Hub와 통신하는 디바이스 클라이언트를 만듭니다.

    • Device 개체를 만들어 디바이스 쌍 속성을 저장합니다.

    DeviceClient client = new DeviceClient(connString, protocol);
    
    // Create a Device object to store the device twin properties
    Device dataCollector = new Device() {
      // Print details when a property value changes
      @Override
      public void PropertyCall(String propertyKey, Object propertyValue, Object context) {
        System.out.println(propertyKey + " changed to " + propertyValue);
      }
    };
    
  12. 다음 코드를 main 메서드에 추가하여 connectivityType reported 속성을 만들고 IoT Hub로 보냅니다.

    try {
      // Open the DeviceClient and start the device twin services.
      client.open();
      client.startDeviceTwin(new DeviceTwinStatusCallBack(), null, dataCollector, null);
    
      // Create a reported property and send it to your IoT hub.
      dataCollector.setReportedProp(new Property("connectivityType", "cellular"));
      client.sendReportedProperties(dataCollector.getReportedProp());
    }
    catch (Exception e) {
      System.out.println("On exception, shutting down \n" + " Cause: " + e.getCause() + " \n" + e.getMessage());
      dataCollector.clean();
      client.closeNow();
      System.out.println("Shutting down...");
    }
    
  13. main 메서드의 끝에 다음 코드를 추가합니다. Enter 키를 좀 천천히 눌러 IoT Hub가 디바이스 쌍 작업의 상태를 보고할 때까지 기다립니다.

    System.out.println("Press any key to exit...");
    
    Scanner scanner = new Scanner(System.in);
    scanner.nextLine();
    
    dataCollector.clean();
    client.close();
    
  14. main 메서드의 서명을 수정하여 다음과 같은 예외를 포함합니다.

    public static void main(String[] args) throws URISyntaxException, IOException
    
  15. simulated-device\src\main\java\com\mycompany\app\App.java 파일을 저장한 후 닫습니다.

  16. simulated-device 앱을 빌드하고 오류를 수정합니다. 명령 프롬프트에서 simulated-device 폴더로 이동한 후 다음 명령을 실행합니다.

    mvn clean package -DskipTests
    

원하는 속성을 업데이트하고 쌍을 쿼리하는 서비스 앱 만들기

이 섹션에서는 myDeviceId와 연결된 IoT Hub의 디바이스 쌍에 태그로 위치 메타데이터를 추가하는 Java 앱을 만듭니다. 앱은 미국에 있는 디바이스에 대한 IoT 허브를 쿼리한 다음, 셀룰러 네트워크 연결을 보고하는 디바이스를 쿼리합니다.

  1. 개발 머신에서 iot-node.js-getstarted라는 빈 폴더를 만듭니다.

  2. 명령 프롬프트에서 다음 명령을 사용하여 iot-java-twin-getstarted 폴더에서 add-tags-query라는 Maven 프로젝트를 만듭니다.

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=add-tags-query -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  3. 명령 프롬프트에서 add-tags-query 폴더로 이동합니다.

  4. 텍스트 편집기를 사용하여 add-tags-query 폴더에서 pom.xml 파일을 열고 종속성 노드에 다음 종속성을 추가합니다. 이러한 종속성을 통해 IoT Hub와 통신하도록 앱에서 iot-service-client 패키지를 사용할 수 있습니다.

    <dependency>
      <groupId>com.microsoft.azure.sdk.iot</groupId>
      <artifactId>iot-service-client</artifactId>
      <version>1.17.1</version>
      <type>jar</type>
    </dependency>
    

    참고 항목

    Maven 검색을 사용하여 iot-service-client의 최신 버전을 확인할 수 있습니다.

  5. 종속성 노드 뒤에 다음 빌드 노드를 추가합니다. 이 구성에서는 Maven에 Java 1.8을 사용하여 앱을 빌드하도록 지시합니다.

    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.3</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
          </configuration>
        </plugin>
      </plugins>
    </build>
    
  6. pom.xml 파일을 저장하고 닫습니다.

  7. 텍스트 편집기를 사용하여 add-tags-query\src\main\java\com\mycompany\app\App.java 파일을 엽니다.

  8. 파일에 다음 import 문을 추가합니다.

    import com.microsoft.azure.sdk.iot.service.devicetwin.*;
    import com.microsoft.azure.sdk.iot.service.exceptions.IotHubException;
    
    import java.io.IOException;
    import java.util.HashSet;
    import java.util.Set;
    
  9. 다음 클래스 수준 변수를 App 클래스에 추가합니다. {youriothubconnectionstring}IoT Hub 연결 문자열 가져오기에서 복사한 IoT hub 연결 문자열로 바꿉니다.

    public static final String iotHubConnectionString = "{youriothubconnectionstring}";
    public static final String deviceId = "myDeviceId";
    
    public static final String region = "US";
    public static final String plant = "Redmond43";
    
  10. 다음 throws 절을 포함하도록 main 메서드 서명을 업데이트합니다.

    public static void main( String[] args ) throws IOException
    
  11. main 메서드의 코드를 다음 코드와 바꾸어 DeviceTwinDeviceTwinDevice 개체를 만듭니다. DeviceTwin 개체는 IoT 허브와의 통신을 처리합니다. DeviceTwinDevice 개체는 해당 속성 및 태그로 디바이스 쌍을 나타냅니다.

    // Get the DeviceTwin and DeviceTwinDevice objects
    DeviceTwin twinClient = DeviceTwin.createFromConnectionString(iotHubConnectionString);
    DeviceTwinDevice device = new DeviceTwinDevice(deviceId);
    
  12. 다음 try/catch 블록을 main 메서드에 추가합니다.

    try {
      // Code goes here
    } catch (IotHubException e) {
      System.out.println(e.getMessage());
    } catch (IOException e) {
      System.out.println(e.getMessage());
    }
    
  13. 디바이스 쌍에서 regionplant 디바이스 쌍 태그를 업데이트하려면 try 블록에 다음 코드를 추가합니다.

    // Get the device twin from IoT Hub
    System.out.println("Device twin before update:");
    twinClient.getTwin(device);
    System.out.println(device);
    
    // Update device twin tags if they are different
    // from the existing values
    String currentTags = device.tagsToString();
    if ((!currentTags.contains("region=" + region) && !currentTags.contains("plant=" + plant))) {
      // Create the tags and attach them to the DeviceTwinDevice object
      Set<Pair> tags = new HashSet<Pair>();
      tags.add(new Pair("region", region));
      tags.add(new Pair("plant", plant));
      device.setTags(tags);
    
      // Update the device twin in IoT Hub
      System.out.println("Updating device twin");
      twinClient.updateTwin(device);
    }
    
    // Retrieve the device twin with the tag values from IoT Hub
    System.out.println("Device twin after update:");
    twinClient.getTwin(device);
    System.out.println(device);
    
  14. IoT 허브에서 디바이스 쌍을 쿼리하려면 이전 단계에서 추가한 코드 뒤의 try 블록에 다음 코드를 추가합니다. 코드는 두 개의 쿼리를 실행합니다. 각 쿼리는 최대 100대의 디바이스를 반환합니다.

    // Query the device twins in IoT Hub
    System.out.println("Devices in Redmond:");
    
    // Construct the query
    SqlQuery sqlQuery = SqlQuery.createSqlQuery("*", SqlQuery.FromType.DEVICES, "tags.plant='Redmond43'", null);
    
    // Run the query, returning a maximum of 100 devices
    Query twinQuery = twinClient.queryTwin(sqlQuery.getQuery(), 100);
    while (twinClient.hasNextDeviceTwin(twinQuery)) {
      DeviceTwinDevice d = twinClient.getNextDeviceTwin(twinQuery);
      System.out.println(d.getDeviceId());
    }
    
    System.out.println("Devices in Redmond using a cellular network:");
    
    // Construct the query
    sqlQuery = SqlQuery.createSqlQuery("*", SqlQuery.FromType.DEVICES, "tags.plant='Redmond43' AND properties.reported.connectivityType = 'cellular'", null);
    
    // Run the query, returning a maximum of 100 devices
    twinQuery = twinClient.queryTwin(sqlQuery.getQuery(), 3);
    while (twinClient.hasNextDeviceTwin(twinQuery)) {
      DeviceTwinDevice d = twinClient.getNextDeviceTwin(twinQuery);
      System.out.println(d.getDeviceId());
    }
    
  15. add-tags-query\src\main\java\com\mycompany\app\App.java 파일을 저장한 후 닫습니다.

  16. add-tags-query 앱을 빌드하고 오류를 수정합니다. 명령 프롬프트에서 add-tags-query 폴더로 이동하고 다음 명령을 실행합니다.

    mvn clean package -DskipTests
    

앱 실행

이제 콘솔 앱을 실행할 준비가 되었습니다.

  1. 명령 프롬프트의 add-tags-query 폴더에서 다음 명령을 실행하여 add-tags-query 서비스 앱을 실행합니다.

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
    

    태그 쿼리 추가 서비스 앱을 실행하기 위한 명령의 출력을 보여 주는 스크린샷

    디바이스 쌍에 추가된 plantregion 태그를 볼 수 있습니다. 첫 번째 쿼리에서 디바이스를 반환하지만 두 번째는 그렇지 않습니다.

  2. 명령 프롬프트의 simulated-device 폴더에서 다음 명령을 실행하여 connectivityType reported 속성을 디바이스 쌍에 추가합니다.

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
    

    디바이스 클라이언트는 연결 유형 reported 속성을 추가합니다.

  3. 명령 프롬프트의 add-tags-query 폴더에서 다음 명령을 실행하여 add-tags-query 서비스 앱을 두 번째로 실행합니다.

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
    

    태그 값을 업데이트하고 디바이스 쿼리를 실행하는 Java IoT Hub 서비스 앱

    이제 디바이스는 connectivityType 속성을 IoT Hub에 전송했으므로 두 번째 쿼리에서 디바이스를 반환합니다.

이 문서에서는 다음 작업을 수행합니다.

  • 백 엔드 앱에서 태그로 디바이스 메타데이터 추가
  • 디바이스 쌍에서 보고된 디바이스 연결 정보
  • SQL과 유사한 IoT Hub 쿼리 언어를 사용하여 디바이스 쌍 정보를 쿼리함

다음 단계

방법을 알아보려면 다음을 참조하세요.