物联网很多业务场景中,时常需要获取设备的实时状态,以便根据不同状态(在线或离线)做不同处理。阿里云物联网平台提供多个云端API来获取设备的状态信息。本文介绍这些API的调用方法。

原理

以下五个API可以获得设备状态。请根据业务需要,选择调用的接口。

API 描述 优缺点
GetDeviceStatus 获取单个设备的状态。 通过会话来获取设备状态,返回结果可能会因为网络和心跳包延迟而延时更新。
BatchGetDeviceState 批量获取多个设备的状态。
QueryDeviceDetail 查询单个设备的详细信息

除设备状态外,还可以获得其他设备信息。

BatchQueryDeviceDetail 批量查询多个设备的详细信息

除设备状态外,还可以获得其他设备信息。

RRpc 向指定设备发送查询状态的请求消息,并同步返回响应。 该接口查询到的设备状态信息准确度高。
说明 本文示例中,只介绍调用RRpc查询设备状态的服务端SDK配置;更完整的设备状态查询配置方法,请参见服务端检测设备是否在线

实现

本文示例使用Java SDK,需准备Java开发环境。

在Maven项目中,需添加如下pom依赖,安装阿里云IoT SDK。

<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>aliyun-java-sdk-core</artifactId>
  <version>3.5.1</version>
</dependency>
<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>aliyun-java-sdk-iot</artifactId>
  <version>6.11.0</version>
</dependency>
<dependency>
  <groupId>commons-codec</groupId>
  <artifactId>commons-codec</artifactId>
  <version>1.13</version>
</dependency>

Config.*参数值中,需传入您的阿里云账号AccessKey信息和设备信息。

  // 地域ID,根据您的物联网平台服务地域获取对应ID,https://help.aliyun.com/document_detail/40654.html
  private static String regionId = "cn-shanghai";
  // 您的阿里云账号AccessKey ID
  private static String accessKeyID = "Config.accessKey";
  // 您的阿里云账号AccesseKey Secret
  private static String accessKeySecret = "Config.accessKeySecret";
  // 要查询的设备所属产品的ProductKey
  private static String productKey = "Config.productKey";
  // 要查询的设备的名称DeviceName
  private static String deviceName = "Config.deviceName";

完整代码示例如下:

/*   
 * Copyright © 2019 Alibaba. All rights reserved.
 */
package com.aliyun.iot.demo.checkstatus;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.codec.binary.Base64;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.iot.model.v20180120.BatchGetDeviceStateRequest;
import com.aliyuncs.iot.model.v20180120.BatchGetDeviceStateResponse;
import com.aliyuncs.iot.model.v20180120.BatchGetDeviceStateResponse.DeviceStatus;
import com.aliyuncs.iot.model.v20180120.BatchQueryDeviceDetailRequest;
import com.aliyuncs.iot.model.v20180120.BatchQueryDeviceDetailResponse;
import com.aliyuncs.iot.model.v20180120.BatchQueryDeviceDetailResponse.DataItem;
import com.aliyuncs.iot.model.v20180120.GetDeviceStatusRequest;
import com.aliyuncs.iot.model.v20180120.GetDeviceStatusResponse;
import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailRequest;
import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailResponse;
import com.aliyuncs.iot.model.v20180120.RRpcRequest;
import com.aliyuncs.iot.model.v20180120.RRpcResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

public class GetDeviceStatusByApi {

  // ===================需要用户填写的参数开始===========================
  // 修改Config.*的参数为您的实际信息
  // 地域ID,根据您的物联网平台服务地域获取对应ID,https://help.aliyun.com/document_detail/40654.html
  private static String regionId = "cn-shanghai";
  // 用户账号AccessKey ID
  private static String accessKeyID = "Config.accessKey";
  // 用户账号AccesseKey Secret
  private static String accessKeySecret = "Config.accessKeySecret";
  // 要查询的设备所属的产品ProductKey
  private static String productKey = "Config.productKey";
  // 要查询的设备名称deviceName
  private static String deviceName = "Config.deviceName";
  // ===================需要用户填写的参数结束===========================

  private static DefaultAcsClient client = null;

  private static DefaultAcsClient getClient(String accessKeyID, String accessKeySecret) {

    if (client != null) {
      return client;
    }

    try {
      IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyID, accessKeySecret);
      DefaultProfile.addEndpoint(regionId, regionId, "Iot", "iot." + regionId + ".aliyuncs.com");
      client = new DefaultAcsClient(profile);
    } catch (Exception e) {
      System.out.println("create OpenAPI Client failed !! exception:" + e.getMessage());
    }

    return client;
  }

  /**
   * 设备状态获取
   * 方法一、二、三、四是基于状态查询的,获取的状态值可能会因为网络和心跳包延迟而延时更新;
   * 方法五是基于同步通信的,结果比较精准
   * 
   * @param args
   * @throws ServerException
   * @throws ClientException
   */
  public static void main(String[] args) throws ServerException, ClientException {

    // 获取服务端请求客户端
    DefaultAcsClient client = getClient(accessKeyID, accessKeySecret);

    GetDeviceStatusByApi api = new GetDeviceStatusByApi();

    // 方法一
    api.ByGetDeviceStatus(client);

    // 方法二
    api.ByBatchGetDeviceState(client);

    // 方法三
    api.ByQueryDeviceDetail(client);

    // 方法四
    api.ByBatchQueryDeviceDetail(client);

    // 方法五
    api.ByRRpc(client);
  }

  /**
   * 查询单设备运行状态
   * GetDeviceStatus https://help.aliyun.com/document_detail/69617.html
   * 
   * @param client 服务端请求客户端
   * @throws ServerException
   * @throws ClientException
   */
  public void ByGetDeviceStatus(DefaultAcsClient client) throws ServerException, ClientException {

    // 填充请求
    GetDeviceStatusRequest request = new GetDeviceStatusRequest();
    request.setProductKey(productKey); // 目标设备产品key
    request.setDeviceName(deviceName); // 目标设备名

    // 获取结果
    GetDeviceStatusResponse response = (GetDeviceStatusResponse) client.getAcsResponse(request);
    if (response != null && response.getSuccess()) {
      GetDeviceStatusResponse.Data data = response.getData();
      // ONLINE:设备在线。
      // OFFLINE:设备离线。
      // UNACTIVE:设备未激活。
      // DISABLE:设备已禁用。
      if ("ONLINE".equals(data.getStatus())) {
        System.out.println("GetDeviceStatus 检测:" + deviceName + " 设备在线");
      } else { // 其他状态归结为设备不在线,也可以根据业务情况自行区分处理
        System.out.println("GetDeviceStatus 检测:" + deviceName + " 设备不在线");
      }
    } else {
      System.out.println("GetDeviceStatus 检测:" + "接口调用不成功,可能设备 " + deviceName + " 不存在");
    }
  }

  /**
   * 批量查询设备运行状态
   * BatchGetDeviceState https://help.aliyun.com/document_detail/69906.html
   * 
   * @param client 服务端请求客户端
   * @throws ServerException
   * @throws ClientException
   */
  public void ByBatchGetDeviceState(DefaultAcsClient client) throws ServerException, ClientException {

    // 填充请求
    BatchGetDeviceStateRequest request = new BatchGetDeviceStateRequest();
    request.setProductKey(productKey); // 目标设备产品key
    List<String> deviceNames = new ArrayList<String>(); // 目标设备名列表
    deviceNames.add(deviceName);
    request.setDeviceNames(deviceNames);

    // 获取结果
    BatchGetDeviceStateResponse response = (BatchGetDeviceStateResponse) client.getAcsResponse(request);
    if (response != null && response.getSuccess()) {
      List<DeviceStatus> dsList = response.getDeviceStatusList();
      for (DeviceStatus ds : dsList) {
        // ONLINE:设备在线。
        // OFFLINE:设备离线。
        // UNACTIVE:设备未激活。
        // DISABLE:设备已禁用。
        if ("ONLINE".equals(ds.getStatus())) {
          System.out.println("BatchGetDeviceState 检测:" + ds.getDeviceName() + " 设备在线");
        } else { // 其他状态归结为设备不在线,也可以根据业务情况自行区分处理
          System.out.println("BatchGetDeviceState 检测:" + ds.getDeviceName() + " 设备不在线");
        }
      }
    } else {
      System.out.println("BatchGetDeviceState 检测:" + "接口调用不成功,可能设备 " + deviceName + " 不存在");
    }
  }

  /**
   * 查询单设备详细信息
   * QueryDeviceDetail https://help.aliyun.com/document_detail/69594.html
   * 
   * @param client 服务端请求客户端
   * @throws ServerException
   * @throws ClientException
   */
  public void ByQueryDeviceDetail(DefaultAcsClient client) throws ServerException, ClientException {

    // 填充请求
    QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
    request.setProductKey(productKey); // 目标设备产品key
    request.setDeviceName(deviceName); // 目标设备名

    // 获取结果
    QueryDeviceDetailResponse response = (QueryDeviceDetailResponse) client.getAcsResponse(request);
    if (response != null && response.getSuccess()) {
      QueryDeviceDetailResponse.Data data = response.getData();
      // ONLINE:设备在线。
      // OFFLINE:设备离线。
      // UNACTIVE:设备未激活。
      // DISABLE:设备已禁用。
      if ("ONLINE".equals(data.getStatus())) {
        System.out.println("QueryDeviceDetail 检测:" + deviceName + " 设备在线");
      } else { // 其他状态归结为设备不在线,也可以根据业务情况自行区分处理
        System.out.println("QueryDeviceDetail 检测:" + deviceName + " 设备不在线");
      }
    } else {
      System.out.println("QueryDeviceDetail 检测:" + "接口调用不成功,可能设备 " + deviceName + " 不存在");
    }
  }

  /**
   * 批量查询设备详细信息
   * BatchQueryDeviceDetai https://help.aliyun.com/document_detail/123470.html
   * 
   * @param client 服务端请求客户端
   * @throws ServerException
   * @throws ClientException
   */
  public void ByBatchQueryDeviceDetail(DefaultAcsClient client) throws ServerException, ClientException {

    // 填充请求
    BatchQueryDeviceDetailRequest request = new BatchQueryDeviceDetailRequest();
    request.setProductKey(productKey); // 目标设备产品key
    List<String> deviceNames = new ArrayList<String>(); // 目标设备名列表
    deviceNames.add(deviceName);
    request.setDeviceNames(deviceNames);

    // 获取结果
    BatchQueryDeviceDetailResponse response = (BatchQueryDeviceDetailResponse) client.getAcsResponse(request);
    if (response != null && response.getSuccess()) {
      List<DataItem> diList = response.getData();
      for (DataItem di : diList) {
        // ONLINE:设备在线。
        // OFFLINE:设备离线。
        // UNACTIVE:设备未激活。
        // DISABLE:设备已禁用。
        if ("ONLINE".equals(di.getStatus())) {
          System.out.println("BatchQueryDeviceDetail 检测:" + di.getDeviceName() + " 设备在线");
        } else { // 其他状态归结为设备不在线,也可以根据业务情况自行区分处理
          System.out.println("BatchQueryDeviceDetail 检测:" + di.getDeviceName() + " 设备不在线");
        }
      }
    } else {
      System.out.println("BatchQueryDeviceDetail 检测:" + "接口调用不成功,可能设备 " + deviceName + " 不存在");
    }
  }

  /**
   * RRPC 检测设备状态
   * RRpc https://help.aliyun.com/document_detail/69797.html
   * 
   * @param client 服务端请求客户端
   * @throws ServerException
   * @throws ClientException
   */
  public void ByRRpc(DefaultAcsClient client) throws ServerException, ClientException {

    // 填充请求
    RRpcRequest request = new RRpcRequest();
    request.setProductKey(productKey);// 目标设备产品key
    request.setDeviceName(deviceName);// 目标设备名
    request.setRequestBase64Byte(Base64.encodeBase64String("Hello World".getBytes())); // 消息内容,必须base64编码字符串
    request.setTimeout(5000); // 响应超时设置,可根据实际需要填写数值

    // 获取结果
    RRpcResponse response = (RRpcResponse) client.getAcsResponse(request);
    if (response != null) { // 不要使用response.getSuccess()判断,非SUCCESS都是false;直接使用RrpcCode判断即可
      // UNKNOWN:系统异常
      // SUCCESS:成功
      // TIMEOUT:设备响应超时
      // OFFLINE:设备离线
      // HALFCONN:设备离线(设备连接断开,但是断开时间未超过一个心跳周期)
      if ("SUCCESS".equals(response.getRrpcCode())) {
        System.out.println("RRPC 检测:" + deviceName + " 设备在线");
      } else if (response.getRrpcCode() == null) {
        System.out.println("RRPC 检测:" + deviceName + " 设备可能不存在");
      } else { // 其他状态归结为设备不在线,也可以根据业务情况自行区分处理
        System.out.println("RRPC 检测:" + deviceName + " 设备不在线:");
      }
      // RRPC 还可以实现更复杂的设备状态检测方法
      // 请参考 https://help.aliyun.com/document_detail/101133.html
    } else {
      System.out.println("RRPC 检测:" + "接口调用不成功");
    }
  }
}