次の方法で共有

设备孪生入门 (Java)

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

注释

本文中所述的功能仅在 IoT 中心的标准层中可用。 有关基本层和标准/免费 IoT 中心层的详细信息,请参阅 为解决方案选择正确的 IoT 中心层和大小

使用设备孪生可以:

  • 从解决方案后端存储设备元数据。

  • 报告当前状态信息,例如可用功能和条件,例如设备应用中使用的连接方法。

  • 在设备应用和后端应用之间同步长时间运行的工作流的状态,例如固件和配置更新。

  • 查询设备元数据、配置或状态。

设备孪生专为同步和查询设备配置和条件而设计。 有关设备孪生的详细信息,包括何时使用设备孪生,请参阅 了解设备孪生

IoT 中心存储设备孪生体,其中包含以下元素:

  • 标记。 设备元数据只能由解决方案后端访问。

  • 所需属性。 解决方案后端可修改的 JSON 对象,并且设备应用程序可对其进行观察。

  • 报告的属性。 设备应用可修改的 JSON 对象,解决方案后端可读。

标记和属性不能包含数组,但可以包含嵌套对象。

下图显示了设备孪生结构:

设备孪生概念图的屏幕截图。

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

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

  • add-tags-query:一个后端应用,用于添加标记和查询设备孪生。
  • simulated-device:一个连接到 IoT 中心的模拟设备应用,并报告其连接条件。

注释

有关可用于生成设备和后端应用的 SDK 工具的详细信息,请参阅 Azure IoT SDK

先决条件

  • IoT 中心。 使用 CLIAzure 门户创建一个。

  • 已注册的设备。 在 Azure 门户中注册一个。

  • Java SE 开发工具包 8。 请确保在长期支持下选择 Java 8,以获取 JDK 8 的下载。

  • Maven 3

  • 确保已在防火墙中打开端口 8883。 本文中的设备示例使用通过端口 8883 进行通信的 MQTT 协议。 某些企业和教育网络环境中可能会阻止此端口。 有关解决此问题的详细信息和方法,请参阅“连接到 IoT 中心”(MQTT)。

获取 IoT 中心连接字符串

在本文中,你将创建一个后端服务,该服务将所需属性添加到设备孪生,然后查询标识注册表以查找报告的属性已相应地更新的所有设备。 服务需要 服务连接 权限来修改设备孪生的所需属性,并且需要 注册表读取 权限才能查询标识注册表。 没有仅包含这两个权限的默认共享访问策略,因此需要创建一个。

若要创建一个共享访问策略,用于授予 服务连接注册表读取 权限并获取此策略的连接字符串,请执行以下步骤:

  1. Azure 门户中,选择 资源组。 选择中心所在的资源组,然后从资源列表中选择中心。

  2. 在中心的左侧窗格中,选择 “共享访问策略”。

  3. 从策略列表上方的顶部菜单中,选择 “添加共享策略访问策略”。

  4. 在右侧的 “添加共享访问策略 ”窗格中,输入策略的描述性名称,例如 serviceAndRegistryRead。 在“权限”下,选择“注册表读取”和服务连接,然后选择“添加”。

    显示如何添加新共享访问策略的屏幕截图。

  5. 从策略列表中选择新策略。

  6. 选择 主连接字符串 的复制图标并保存值。

    显示如何检索连接字符串的屏幕截图。

有关 IoT 中心共享访问策略和权限的详细信息,请参阅 访问控制和权限

创建更新报告属性的设备应用

在本部分中,将创建一个 Java 控制台应用,该应用以 myDeviceId 的形式连接到中心,然后更新其设备孪生的报告属性,以确认它已使用手机网络进行连接。

  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-device-client 包与 IoT 中心通信。

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

    注释

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

  4. 将以下依赖项添加到 依赖项 节点。 此依赖项将 Apache SLF4J 日志记录外观配置为 NOP,设备客户端 SDK 使用它来进行日志记录。 此配置是可选的,但如果省略该配置,则运行应用时可能会在控制台中看到警告。 有关设备客户端 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 中心注册设备时看到的设备连接字符串:

    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 中心通信。

    • 创建 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 报告属性并将其发送到 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.closeNow();
      System.out.println("Shutting down...");
    }
    
  13. 将以下代码添加到 main 方法的末尾。 等待按下 Enter 键,以便 IoT 中心有时间报告设备孪生操作的状态。

    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 文件夹并运行以下命令:

    mvn clean package -DskipTests
    

创建用于更新所需属性和查询孪生的服务应用

在本部分中,将创建一个 Java 应用,该应用将位置元数据作为标记添加到与 myDeviceId 关联的 IoT 中心的设备孪生。 该应用查询 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 文件,并将以下依赖项添加到依赖项节点。 通过此依赖项,可以使用应用中的 iot-service-client 包与 IoT 中心通信:

    <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 中心连接字符串 中复制的 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 方法中的代码替换为以下代码,以创建 DeviceTwin 和 DeviceTwinDevice 对象。 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. 若要更新设备孪生中的区域工厂设备孪生标记,请在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"
    

    显示用于运行添加标记查询服务应用的命令的输出的屏幕截图。

    可以看到添加到设备孪生的 工厂区域 标记。 第一个查询返回你的设备,但第二个不会。

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

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

    设备客户端添加连接类型报告属性

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

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

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

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

本文内容:

  • 从后端应用添加设备元数据作为标记
  • 设备孪生中报告的设备连接信息
  • 使用类似于 SQL 的 IoT 中心查询语言查询设备孪生信息

后续步骤

若要了解如何操作: