设备孪生入门 (Java)

设备孪生是存储设备状态信息(元数据、配置和条件)的 JSON 文档。 IoT 中心为连接到它的每台设备保留一个设备孪生。

Note

本文中所述的功能仅可在 IoT 中心的标准层中使用。 有关基本和标准 IoT 中心层的详细信息,请参阅如何选择合适的 IoT 中心层

使用设备孪生可以:

  • 存储来自解决方案后端的设备元数据。
  • 通过设备应用报告当前状态信息,例如可用功能和条件(例如,使用的连接方法)。
  • 同步设备应用和后端应用之间的长时间运行的工作流的状态(例如固件和配置更新)。
  • 查询设备的元数据、配置或状态。

设备孪生旨在执行同步以及查询设备的配置和条件。 了解设备孪生中提供了有关何时使用设备孪生的详细信息。

设备孪生存储在 IoT 中心内,其中包含:

  • 标记,仅可由解决方案后端访问的设备元数据;
  • 所需属性,可以由解决方案后端修改以及由设备应用观察的 JSON 对象;以及
  • 报告属性,可由设备应用修改以及由解决方案后端读取的 JSON 对象。 标记和属性不能包含数组,但可以嵌套对象。

此外,解决方案后端可以根据上述所有数据查询设备孪生。 有关设备孪生的详细信息,请参阅了解设备孪生,有关查询的参考,请参阅 IoT 中心查询语言

本教程演示如何:

  • 创建将标记添加到设备孪生的后端应用,以及将其连接通道作为设备孪生上的报告属性进行报告的模拟设备应用。
  • 使用标记上的筛选器和之前创建的属性通过后端应用查询设备。

在本教程中,你将创建两个 Java 控制台应用:

  • add-tags-query:一个 Java 后端应用,用于添加标记并查询设备孪生。
  • simulated-device:Java 设备应用,它连接到 IoT 中心,并使用报告的属性报告其连接状态。

Note

Azure IoT SDK 一文介绍了可用于构建设备和后端应用的 Azure IoT SDK。

要完成本教程,需要:

创建 IoT 中心

此部分介绍如何使用 Azure 门户创建 IoT 中心。

  1. 登录到 Azure 门户

  2. 选择+“创建资源”,然后选择“物联网”。

  3. 在右侧列表中单击“Iot 中心”。 随即显示 IoT 中心创建过程的第一个屏幕。

    显示了在 Azure 门户中创建中心的屏幕截图

    填充字段。

    订阅:请选择要用于 IoT 中心的订阅。

    资源组:可创建新的资源组或使用现有资源组。 若要新建一个,请单击“新建”,并填写要使用的名称。 若要使用现有资源组,请单击“使用现有资源组”并从下拉列表中选择该组。 有关详细信息,请参阅使用资源组管理 Azure 资源

    区域:这是要在其中设置中心的区域。 从下拉列表中选择最靠近自己的位置。

    IoT 中心名称:输入 IoT 中心的名称。 此名称必须全局唯一。 如果输入的名称可用,会显示一个绿色复选标记。

    Important

    IoT 中心将公开为 DNS 终结点,因此,命名时请务必避免包含任何敏感信息。

  4. 单击“下一步: 大小和规模”,以便继续创建 IoT 中心。

    屏幕截图显示使用 Azure 门户为新的 IoT 中心设置大小和缩放级别

    在此屏幕上,可以采用默认值,只需在底部单击“查看+创建”即可。

    定价和缩放层级:可以根据需要的功能数以及每天通过解决方案发送的消息数从多个层中进行选择。 免费层适用于测试和评估。 它允许 500 台设备连接到 IoT 中心,并且每天最多传输 8,000 条信息。 每个 Azure 订阅可以在免费层中创建一个 IoT 中心。

    IoT 中心单位:每日每单位允许的消息数取决于中心的定价层。 例如,如果希望 IoT 中心支持 700,000 条消息输入,则选择两个 S1 层单位。

    有关其他层选项的详细信息,请参阅选择合适的 IoT 中心层

    高级/设备到云的分区:此属性将设备到云消息与这些消息的同步读取器数目相关联。 大多数 IoT 中心只需要 4 个分区。

  5. 单击“查看+创建”可查看选择。 会显示类似于以下的屏幕。

    屏幕截图显示用于创建新 IoT 中心的信息

  6. 单击“创建”以创建新的 IoT 中心。 创建中心需要几分钟时间。

检索 IoT 中心的连接字符串

创建中心以后,请检索中心的连接字符串。 该字符串用于将设备和应用程序连接到中心。

  1. 单击中心,查看“IoT 中心”窗格,其中包含“设置”等内容。 单击“共享访问策略”。

  2. 在“共享访问策略”中,选择 iothubowner 策略。

  3. 在“共享访问密钥”下,复制“连接字符串 -- 主密钥”供以后使用。

    显示如何检索连接字符串

    有关详细信息,请参阅“IoT 中心开发人员指南”中的访问控制

在 IoT 中心内注册新设备

本部分在 IoT 中心的标识注册表中创建设备标识。 设备无法连接到 IoT 中心,除非它在标识注册表中具有条目。 有关详细信息,请参阅 IoT 中心开发人员指南的“标识注册表”部分

  1. 在 IoT 中心导航菜单中,打开“IoT 设备”,然后单击“添加”,在 IoT 中心注册新设备。

    在门户中创建设备标识

  2. 提供新设备的名称(例如 myDeviceId),然后单击“保存”。 此操作会为 IoT 中心创建新设备标识。

    添加新设备

    Important

    收集的日志中可能会显示设备 ID 用于客户支持和故障排除,因此,在为日志命名时,请务必避免包含任何敏感信息。

  3. 创建设备后,在“IoT 设备”窗格的列表中打开该设备。 复制“连接字符串 ---主密钥”供以后使用。

    设备连接字符串

Note

IoT 中心标识注册表仅存储用于实现 IoT 中心安全访问的设备标识。 它存储设备 ID 和密钥作为安全凭据,以及启用/禁用标志让你禁用对单个设备的访问。 如果应用程序需要存储其他特定于设备的元数据,则应使用特定于应用程序的存储。 有关详细信息,请参阅 IoT 中心开发人员指南

创建服务应用

本部分将创建一个 Java 应用,用于将位置元数据作为标记添加到 IoT 中心内与 myDeviceId 关联的设备孪生。 该应用首先在 IoT 中心查询设备,然后查询报告已建立移动电话网络连接的设备。

  1. 在开发计算机上,创建名为 iot-java-twin-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 文件,在 dependencies 节点中添加以下依赖项。 通过此依赖项可以使用应用中的 iot-service-client 包来与 IoT 中心通信:

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

    Note

    可以使用 Maven 搜索检查是否有最新版本的 iot-service-client

  5. dependencies 节点后添加以下 build 节点。 此配置指示 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 中心”部分记下的 IoT 中心连接字符串:

    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. 更新 main 方法签名,以包含以下 throws 子句:

    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

创建设备应用

本部分创建一个 Java 控制台应用,用于设置要发送到 IoT 中心的报告属性值。

  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 文件,在 dependencies 节点中添加以下依赖项。 通过此依赖项可以使用应用中的 iot-device-client 包来与 IoT 中心进行通信:

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

    Note

    可以使用 Maven 搜索检查是否有最新版本的 iot-device-client

  4. dependencies 节点后添加以下 build 节点。 此配置指示 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>
    
  5. 保存并关闭 pom.xml 文件。

  6. 使用文本编辑器打开 simulated-device\src\main\java\com\mycompany\app\App.java 文件。

  7. 在该文件中添加以下 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;
    
  8. 将以下类级变量添加到 App 类。 将 {youriothubname} 替换为 IoT 中心名称,将 {yourdevicekey} 替换为在“创建设备标识”部分中生成的设备密钥值:

    private static String connString = "HostName={youriothubname}.azure-devices.cn;DeviceId=myDeviceID;SharedAccessKey={yourdevicekey}";
    private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
    private static String deviceId = "myDeviceId";
    

    本示例应用在实例化 DeviceClient 对象时使用 protocol 变量。

  9. 将以下代码添加到 main 方法,以便:

    • 创建用来与 IoT 中心通信的设备客户端。
    • 创建一个 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);
      }
      };
      
  10. 将以下代码添加到 main 方法,创建 connectivityType 报告属性并将其发送到 IoT 中心:

    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.close();
      System.out.println("Shutting down...");
    }
    
  11. 将以下代码添加到 main 方法的末尾。 按 Enter 键,等待一段时间让 IoT 中心报告设备孪生操作的状态:

    System.out.println("Press any key to exit...");
    
    Scanner scanner = new Scanner(System.in);
    scanner.nextLine();
    
    dataCollector.clean();
    client.close();
    
  12. 保存并关闭 simulated-device\src\main\java\com\mycompany\app\App.java 文件。

  13. 生成 simulated-device 应用并更正任何错误。 在命令提示符下,导航到 simulated-device 文件夹并运行以下命令:

    mvn clean package -DskipTests

运行应用

现在可以运行控制台应用了。

  1. add-tags-query 文件夹中的命令提示符下,运行以下命令以运行 add-tags-query 服务应用:

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

    Java IoT 中心服务应用会更新标记值并运行设备查询

    可以看到,plantregion 标记已添加到设备孪生。 第一个查询返回设备,但第二个查询则不会。

  2. simulated-device 文件夹中的命令提示符下,运行以下命令将 connectivityType 报告属性添加到设备孪生:

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

    设备客户端会添加 **connectivityType** 报告属性

  3. add-tags-query 文件夹中的命令提示符下,再次运行以下命令以运行 add-tags-query 服务应用:

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

    Java IoT 中心服务应用会更新标记值并运行设备查询

    现在,设备已将 connectivityType 属性发送到 IoT 中心,第二个查询返回了设备。

后续步骤

本教程中,在 Azure 门户中配置了新的 IoT 中心,并在 IoT 中心的标识注册表中创建了设备标识。 已从后端应用以标记形式添加了设备元数据,并编写了一个设备应用用于报告设备孪生中的设备连接信息。 此外,还学习了如何使用类似于 SQL 的 IoT 中心查询语言查询设备孪生信息。

充分利用以下资源:

  • 通过 IoT 中心入门教程学习如何从设备发送遥测数据。
  • 通过使用直接方法教程学习如何以交互方式控制设备(例如从用户控制的应用打开风扇)。