物聯網很多業務場景中,時常需要獲取設備的實時狀態,以便根據不同狀態(在線或離線)做不同處理。阿里云物聯網平臺提供多個云端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,http://bestwisewords.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,http://bestwisewords.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 http://bestwisewords.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 http://bestwisewords.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 http://bestwisewords.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 http://bestwisewords.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 http://bestwisewords.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 還可以實現更復雜的設備狀態檢測方法
      // 請參考 http://bestwisewords.com/document_detail/101133.html
    } else {
      System.out.println("RRPC 檢測:" + "接口調用不成功");
    }
  }
}