使用直接方法 (Java)

Azure IoT 中心是一项完全托管的服务,可在数百万个设备和一个解决方案后端之间实现安全可靠的双向通信。 以前的教程(IoT 中心入门使用 IoT 中心发送云到设备的消息 )介绍了 IoT 中心的设备到云和云到设备的基本消息传递功能。 用户还可以通过 IoT 中心从云调用设备上的非持久方法。 直接方法表示与设备进行的请求-答复式交互,类似于 HTTP 调用,因为它们不管是成功还是失败,速度都非常快(在用户指定的超时过后),会让用户知道调用的状态。 调用设备上的直接方法更详细地介绍了各种直接方法,指导用户何时使用直接方法而不是云到设备消息或所需属性。

本教程演示如何:

  • 使用 Azure 门户创建 IoT 中心,以及如何在 IoT 中心创建设备标识。
  • 创建一个模拟设备应用,该应用包含可通过云调用的直接方法。
  • 创建一个控制台应用,该应用通过 IoT 中心调用模拟设备应用中的直接方法。

Note

目前只能在通过 MQTT 协议连接到 IoT 中心的设备上使用直接方法。 有关如何转换现有设备应用以使用 MQTT 的说明,请参阅 MQTT 支持 一文。

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

  • invoke-direct-method:一个 Java 后端应用,它调用模拟设备应用上的方法并显示响应。
  • 模拟设备:一个 Java 应用,它模拟使用创建的设备标识连接到 IoT 中心的设备。 此应用对后端直接调用做出响应。

Note

有关 SDK 的信息(可以使用这些 SDK 构建在设备和解决方案后端上运行的应用程序),请参阅 Azure IoT SDK

要完成本教程,需要:

创建 IoT 中心

创建模拟设备应用要连接到的 IoT 中心。 以下步骤说明如何使用 Azure 门户来完成此任务。

  1. 登录到 Azure 门户
  2. 在“跳转栏”中,依次单击“新建” > “物联网” > “IoT 中心”。

    Azure 门户跳转栏

  3. 在“IoT 中心”边栏选项卡中,选择 IoT 中心的配置。

    IoT 中心边栏选项卡

    • 在“名称”框中,输入 IoT 中心的名称。 如果该“名称”有效且可用,“名称”框中会出现绿色的勾选标记。 > [!IMPORTANT] > IoT 中心将公开为 DNS 终结点,因此,命名时请务必避免包含任何敏感信息。 >
    • 选择 定价和缩放层。 本教程不需要特定的层。 对于本教程,请使用免费 F1 层。
    • 在“资源组”中,创建资源组或选择现有的资源组。 有关详细信息,请参阅使用资源组管理 Azure 资源
    • 在“位置”中,选择托管 IoT 中心的位置。 对于本教程,请选择最近位置。
  4. 选择 IoT 中心配置选项后,单击“创建”。 Azure 可能需要几分钟时间来创建 IoT 中心。 若要检查状态,可以在“启动板”或“通知”面板中监视进度。

    新的 IoT 中心状态

  5. 成功创建 IoT 中心后,请在 Azure 门户中单击 IoT 中心对应的新磁贴,以打开新 IoT 中心的边栏选项卡。 记下“主机名”,并单击“共享访问策略”。

    新的 IoT 中心边栏选项卡

  6. 在“共享访问策略”边栏选项卡中,单击“iothubowner”策略,并复制并记下“iothubowner”边栏选项卡中的 IoT 中心连接字符串。 有关详细信息,请参阅“IoT 中心开发人员指南”中的访问控制

    共享访问策略边栏选项卡

创建设备标识

本部分使用名为 iothub-explorer 的 Node.js 工具为本教程创建设备标识。 设备 ID 区分大小写。

  1. 在命令行环境中运行以下命令:

    npm install -g iothub-explorer@latest

  2. 然后,运行以下命令登录到中心。 将 {iot hub connection string} 替换为前面复制的 IoT 中心连接字符串:

    iothub-explorer login "{iot hub connection string}"

  3. 最后,以下使用命令创建名为 myDeviceId 的新设备标识:

    iothub-explorer create myDeviceId --connection-string

    Important

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

记下结果中的设备连接字符串。 设备应用使用此设备连接字符串以设备身份连接到 IoT 中心。

若要以编程方式创建设备标识,请参阅 IoT 中心入门

创建模拟设备应用程序

在本部分中,你将创建一个 Java 控制台应用,用以响应解决方案后端调用的方法。

  1. 创建一个名为 iot-java-direct-method 的空文件夹。

  2. 在命令提示符下使用以下命令,在 iot-java-direct-method 文件夹中创建一个名为 simulated-device 的 Maven 项目。 以下命令是一条很长的命令:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=simulated-device -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

  3. 在命令提示符下,导航到 simulated-device 文件夹。

  4. 使用文本编辑器,打开 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

  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. 使用文本编辑器打开 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 类。 将 {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";
    private static final int METHOD_SUCCESS = 200;
    private static final int METHOD_NOT_DEFINED = 404;
    

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

  10. 若要向 IoT 中心返回状态代码,向 App 类添加以下嵌套类:

    protected static class DirectMethodStatusCallback implements IotHubEventCallback
    {
      public void execute(IotHubStatusCode status, Object context)
      {
        System.out.println("IoT Hub responded to device method operation with status " + status.name());
      }
    }
    
  11. 若要处理从解决方案后端进行的直接方法调用,向 App 类添加以下嵌套类:

    protected static class DirectMethodCallback implements com.microsoft.azure.sdk.iot.device.DeviceTwin.DeviceMethodCallback
    {
      @Override
      public DeviceMethodData call(String methodName, Object methodData, Object context)
      {
        DeviceMethodData deviceMethodData;
        switch (methodName)
        {
          case "writeLine" :
          {
            int status = METHOD_SUCCESS;
            System.out.println(new String((byte[])methodData));
            deviceMethodData = new DeviceMethodData(status, "Executed direct method " + methodName);
            break;
          }
          default:
          {
            int status = METHOD_NOT_DEFINED;
            deviceMethodData = new DeviceMethodData(status, "Not defined direct method " + methodName);
          }
        }
        return deviceMethodData;
      }
    }
    
  12. 若要创建 DeviceClient 并侦听直接方法调用,将一个 main 方法添加到 App 类中:

    public static void main(String[] args)
      throws IOException, URISyntaxException
    {
      System.out.println("Starting device sample...");
    
      DeviceClient client = new DeviceClient(connString, protocol);
    
      try
      {
        client.open();
        client.subscribeToDeviceMethod(new DirectMethodCallback(), null, new DirectMethodStatusCallback(), null);
        System.out.println("Subscribed to direct methods. Waiting...");
      }
      catch (Exception e)
      {
        System.out.println("On exception, shutting down \n" + " Cause: " + e.getCause() + " \n" +  e.getMessage());
        client.close();
        System.out.println("Shutting down...");
      }
    
      System.out.println("Press any key to exit...");
      Scanner scanner = new Scanner(System.in);
      scanner.nextLine();
      scanner.close();
      client.close();
      System.out.println("Shutting down...");
    }
    
  13. 保存并关闭 simulated-device\src\main\java\com\mycompany\app\App.java 文件

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

    mvn clean package -DskipTests

在设备上调用直接方法

在本部分中,创建一个 Java 控制台应用,用以调用一个直接方法并显示响应。 此控制台应用连接到 IoT 中心来调用该直接方法。

  1. 在命令提示符下使用以下命令,在 iot-java-direct-method 文件夹中创建一个名为 invoke-direct-method 的 Maven 项目。 以下命令是一条很长的命令:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=invoke-direct-method -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

  2. 在命令提示符下,导航到 invoke-direct-method 文件夹。

  3. 使用文本编辑器,打开 invoke-direct-method 文件夹中的 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

  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. 使用文本编辑器打开 invoke-direct-method\src\main\java\com\mycompany\app\App.java 文件。

  7. 在该文件中添加以下 import 语句:

    import com.microsoft.azure.sdk.iot.service.devicetwin.DeviceMethod;
    import com.microsoft.azure.sdk.iot.service.devicetwin.MethodResult;
    import com.microsoft.azure.sdk.iot.service.exceptions.IotHubException;
    
    import java.io.IOException;
    import java.util.concurrent.TimeUnit;
    
  8. 将以下类级变量添加到 App 类。 将 {youriothubconnectionstring} 替换为在“创建 IoT 中心”部分记下的 IoT 中心连接字符串:

    public static final String iotHubConnectionString = "{youriothubconnectionstring}";
    public static final String deviceId = "myDeviceId";
    
    public static final String methodName = "writeLine";
    public static final Long responseTimeout = TimeUnit.SECONDS.toSeconds(30);
    public static final Long connectTimeout = TimeUnit.SECONDS.toSeconds(5);
    public static final String payload = "a line to be written";
    
  9. 若要在模拟设备上调用该方法,将以下代码在添加到 main 方法中:

    System.out.println("Starting sample...");
    DeviceMethod methodClient = DeviceMethod.createFromConnectionString(iotHubConnectionString);
    
    try
    {
        System.out.println("Invoke direct method");
        MethodResult result = methodClient.invoke(deviceId, methodName, responseTimeout, connectTimeout, payload);
    
        if(result == null)
        {
            throw new IOException("Direct method invoke returns null");
        }
        System.out.println("Status=" + result.getStatus());
        System.out.println("Payload=" + result.getPayload());
    }
    catch (IotHubException e)
    {
        System.out.println(e.getMessage());
    }
    
    System.out.println("Shutting down sample...");
    
  10. 保存并关闭 invoke-direct-method\src\main\java\com\mycompany\app\App.java 文件

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

    mvn clean package -DskipTests

运行应用

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

  1. 在命令提示符下,在 simulated-device 文件夹中运行以下命令,开始侦听从 IoT 中心发出的方法调用:

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

    Java IoT 中心模拟设备应用侦听直接方法调用

  2. 在命令提示符下,在 invoke-direct-method 文件夹中运行以下命令,从 IoT 中心调用模拟设备上的方法:

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

    Java IoT 中心服务应用调用直接方法

  3. 模拟设备对直接方法调用做出响应:

    Java IoT 中心模拟设备应用对直接方法调用进行响应

后续步骤

本教程中,在 Azure 门户中配置了新的 IoT 中心,并在 IoT 中心的标识注册表中创建了设备标识。 已通过此设备标识启用模拟设备应用的相关功能,使之能够响应通过云调用的方法。 还创建了一个应用,用于调用设备上的方法并显示来自设备的响应。

若要探索其他 IoT 方案,请参阅在多个设备上计划作业

若要了解如何扩展 IoT 解决方案并在多个设备上计划方法调用,请参阅 Schedule and broadcast jobs (计划和广播作业)教程。