全部產品
Search
文件中心

IoT Platform:物模型通訊

更新時間:Jun 30, 2024

裝置與雲端基於Alink協議進行物模型資料通訊,包括裝置上報屬性或事件訊息到雲端,從雲端下發設定屬性或調用服務訊息到裝置。本實踐案例提供Java Demo,介紹物模型資料通訊代碼配置。

前提條件

建立產品和裝置

首先,需建立產品和裝置,為產品定義功能(即物模型)。

  1. 登入物聯網平台控制台
  2. 執行個體概覽頁簽的全部環境下,找到對應的執行個體,單擊執行個體卡片。

  3. 在左側導覽列,單擊裝置管理 > 產品
  4. 單擊建立產品,自訂產品名稱,選擇自訂品類其他參數使用預設值,然後單擊確認,完成建立產品。
    詳細操作指導,請參見建立產品
  5. 產品詳情功能定義頁簽下,定義物模型。

    本樣本中在物模型的預設模組中,添加以下屬性、服務和事件。

    本文提供了樣本的物模型TSL,您可大量匯入,請參見大量新增物模型

    物模型通訊
  6. 在左側導覽列,單擊裝置,建立裝置。
    本範例程式碼中涉及大量設定裝置屬性和批量調用裝置服務,所以需至少建立兩個裝置。詳細操作指導,請參見大量建立裝置

下載、安裝Demo SDK

本樣本提供的SDK Demo中包含了服務端SDK Demo和裝置端SDK Demo。

  1. 單擊下載iotx-api-demo,並解壓縮。
  2. 開啟Java開發工具,匯入解壓縮後的iotx-api-demo檔案夾。
  3. pom.xml檔案中,添加以下Maven依賴,匯入阿里雲雲端SDK和裝置端SDK。
    <!-- https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-iot -->
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-iot</artifactId>
        <version>7.33.0</version>
    </dependency>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
        <version>3.5.1</version>
    </dependency>
    <dependency>
      <groupId>com.aliyun.alink.linksdk</groupId>
      <artifactId>iot-linkkit-java</artifactId>
      <version>1.2.0</version>
      <scope>compile</scope>
    </dependency>
  4. java/src/main/resources/目錄下的config檔案中,填入初始化資訊。
    user.accessKeyID = <your accessKey ID>
    user.accessKeySecret = <your accessKey Secret>
    iot.regionId = <regionId>
    iot.productCode = Iot
    iot.domain = iot.<regionId>.aliyuncs.com
    iot.version = 2018-01-20
    參數說明
    accessKeyID您的阿里雲帳號的AccessKey ID。

    將游標定位到您的帳號頭像上,選擇AccessKey管理,進入安全資訊管理頁,可建立或查看您的AccessKey。

    accessKeySecret您的阿里雲帳號的AccessKey Secret。查看方法同上AccessKey ID。
    regionId您的物聯網裝置所屬地區ID。地區ID的表達方法,請參見地區和可用性區域

裝置端SDK上報屬性和事件

配置裝置端SDK串連物聯網平台,上報屬性和事件訊息。

Demo中,java/src/main/com.aliyun.iot.api.common.deviceApi目錄下的ThingTemplate檔案是裝置端上報屬性和事件的Demo。

  • 設定串連資訊。

    將代碼中productKeydeviceNamedeviceSecreturl替換為您的裝置認證資訊和MQTT接入網域名稱。接入網域名稱擷取方法,請參見查看和配置執行個體終端節點資訊(Endpoint),接入網域名稱必須攜帶連接埠1883。

    public static void main(String[] args) {
            /**
             * 裝置認證資訊。
             */
            String productKey = "your productKey";
            String deviceName = "your deviceName";
            String deviceSecret = "your deviceSecret";
    
            /* TODO: 替換為您物聯網平台執行個體的接入地址 */
            String  url = "iot-6d***ql.mqtt.iothub.aliyuncs.com:1883";
    
            /**
             * mqtt串連資訊。
             */
            ThingTemplate manager = new ThingTemplate();
    
            DeviceInfo deviceInfo = new DeviceInfo();
            deviceInfo.productKey = productKey;
            deviceInfo.deviceName = deviceName;
            deviceInfo.deviceSecret = deviceSecret;
    
            /**
             * 伺服器端的Java HTTP用戶端使用TSLv1.2。
             */
            System.setProperty("https.protocols", "TLSv2");
            manager.init(deviceInfo, url);
        }
  • 初始化串連。
    public void init(final DeviceInfo deviceInfo, String url) {
            LinkKitInitParams params = new LinkKitInitParams();
            /**
             * 設定mqtt初始化參數。
             */
            IoTMqttClientConfig config = new IoTMqttClientConfig();
            config.productKey = deviceInfo.productKey;
            config.deviceName = deviceInfo.deviceName;
            config.deviceSecret = deviceInfo.deviceSecret;
            config.channelHost = url;
            /**
             * 是否接受離線訊息。
             * 對應mqtt的cleanSession欄位。
             */
            config.receiveOfflineMsg = false;
            params.mqttClientConfig = config;
            ALog.setLevel(LEVEL_DEBUG);
            ALog.i(TAG, "mqtt connetcion info=" + params);
    
            /**
             * 設定初始化,傳入裝置認證資訊。
             */
            params.deviceInfo = deviceInfo;
    
            /**建立串連。**/
            LinkKit.getInstance().init(params, new ILinkKitConnectListener() {
                public void onError(AError aError) {
                    ALog.e(TAG, "Init Error error=" + aError);
                }
    
                public void onInitDone(InitResult initResult) {
                    ALog.i(TAG, "onInitDone result=" + initResult);
    
                    List<Property> properties =   LinkKit.getInstance().getDeviceThing().getProperties();
    
                    ALog.i(TAG, "裝置屬性列表" + JSON.toJSONString(properties));
    
                    List<Event> getEvents  =   LinkKit.getInstance().getDeviceThing().getEvents();
    
                    ALog.i(TAG, "裝置事件列表" + JSON.toJSONString(getEvents));
    
                    /*屬性上報。TODO: 需確保所報的屬性, 比如MicSwitch, 是產品的物模型的一部分. 否則會返回錯誤 */
                    handlePropertySet("MicSwitch", new ValueWrapper.IntValueWrapper(1));
    
                    /* 事件上報. TODO: 需確保所報的事件, 比如Offline_alarm, 是產品的物模型的一部分. 否則會返回錯誤 */
                    Map<String,ValueWrapper> values = new HashMap<>();
                    values.put("eventValue",new ValueWrapper.IntValueWrapper(0));
                    OutputParams outputParams = new OutputParams(values);
                    handleEventSet("Offline_alarm",outputParams);
                }
            });
        }
    說明 代碼中的屬性和事件標識符需與物模型中定義的標識符一致。
  • 設定裝置端上報屬性。
    /**
         * Alink JSON方式裝置端上報屬性。
         * @param identifier:屬性標識符。
         * @param value:上報屬性值。
         * @return
         */
        private void handlePropertySet(String identifier, ValueWrapper value ) {
            ALog.i(TAG, "上報屬性identity=" + identifier);
    
            Map<String, ValueWrapper> reportData = new HashMap<>();
            reportData.put(identifier, value);
    
            LinkKit.getInstance().getDeviceThing().thingPropertyPost(reportData, new IPublishResourceListener() {
    
                public void onSuccess(String s, Object o) {
                    // 屬性上報成功。
                    ALog.i(TAG, "上報成功 onSuccess() called with: s = [" + s + "], o = [" + o + "]");
                }
    
                public void onError(String s, AError aError) {
                    // 屬性上報失敗。
                    ALog.i(TAG, "上報失敗onError() called with: s = [" + s + "], aError = [" + JSON.toJSONString(aError) + "]");
                }
            });
        }
  • 設定裝置端上報事件。
    /**
         * Alink JSON方式裝置端上報事件。
         * @param identifyID:事件標識符。
         * @param params:事件上報參數。
         * @return
         */
        private void handleEventSet(String identifyID, OutputParams params ) {
            ALog.i(TAG, "上報事件 identifyID=" + identifyID + "  params=" + JSON.toJSONString(params));
    
    
            LinkKit.getInstance().getDeviceThing().thingEventPost( identifyID,  params, new IPublishResourceListener() {
    
                public void onSuccess(String s, Object o) {
                    // 事件上報成功。
                    ALog.i(TAG, "上報成功 onSuccess() called with: s = [" + s + "], o = [" + o + "]");
                }
    
                public void onError(String s, AError aError) {
                    // 事件上報失敗。
                    ALog.i(TAG, "上報失敗onError() called with: s = [" + s + "], aError = [" + JSON.toJSONString(aError) + "]");
                }
            });
        }

雲端SDK下發設定屬性和調用服務指令

  • 初始化SDK用戶端。

    Demo中,java/src/main/com.aliyun.iot.client目錄下IotClient檔案是SDK用戶端初始化Demo。

    public class IotClient {
      private static String accessKeyID;
      private static String accessKeySecret;
      private static String regionId;
      private static String domain;
      private static String version;
      public static DefaultAcsClient getClient() {
        DefaultAcsClient client = null;
        Properties prop = new Properties();
        try {
          prop.load(Object.class.getResourceAsStream("/config.properties"));
          accessKeyID = prop.getProperty("user.accessKeyID");
          accessKeySecret = prop.getProperty("user.accessKeySecret");
          regionId = prop.getProperty("iot.regionId");
                domain = prop.getProperty("iot.domain");
                version = prop.getProperty("iot.version");
    
          IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyID, accessKeySecret);
          DefaultProfile.addEndpoint(regionId, regionId, prop.getProperty("iot.productCode"),
              prop.getProperty("iot.domain"));
          // 初始化client。
          client = new DefaultAcsClient(profile);
    
        } catch (Exception e) {
          LogUtil.print("初始化client失敗!exception:" + e.getMessage());
        }
        return client;
      }
        public static String getRegionId() {
            return regionId;
        }
        public static void setRegionId(String regionId) {
            IotClient.regionId = regionId;
        }
        public static String getDomain() {
            return domain;
        }
        public static void setDomain(String domain) {
            IotClient.domain = domain;
        }
        public static String getVersion() {
            return version;
        }
        public static void setVersion(String version) {
            IotClient.version = version;
        }
    }
  • 初始化封裝CommonRequest公用類。

    Demo中,java/src/main/com.aliyun.iot.api.common.openApi目錄下的AbstractManager檔案是封裝雲端API的CommonRequest公用類的Demo。

    public class AbstractManager {
        private static DefaultAcsClient client;
        static {
            client = IotClient.getClient();
        }
        /**
         *  介面請求地址。action:介面名稱。
         *  domain:線上地址。
         *  version:介面版本。
         */
        public static CommonRequest executeTests(String action) {
            CommonRequest request = new CommonRequest();
            request.setDomain(IotClient.getDomain());
            request.setMethod(MethodType.POST);
            request.setVersion(IotClient.getVersion());
            request.setAction(action);
            return request;
        }
  • 配置雲端SDK調用物聯網平台雲端API,下發設定屬性和調用服務的指令。

    java/src/main/com.aliyun.iot.api.common.openApi目錄下的ThingManagerForPopSDk是雲端SDK調用API設定裝置屬性和調用裝置服務的Demo檔案。

    • 調用SetDeviceProperty設定裝置屬性值。
      public static void SetDeviceProperty(String InstanceId, String IotId, String ProductKey, String DeviceName , String Items) {
              SetDevicePropertyResponse response =null;
              SetDevicePropertyRequest request=new SetDevicePropertyRequest();
              request.setDeviceName(DeviceName);
              request.setIotId(IotId);
              request.setItems(Items);
              request.setProductKey(ProductKey);
              request.setIotInstanceId(InstanceId);
      
              try {
                  response = client.getAcsResponse(request);
      
                  if (response.getSuccess() != null && response.getSuccess()) {
                      LogUtil.print("設定裝置屬性成功");
                      LogUtil.print(JSON.toJSONString(response));
                  } else {
                      LogUtil.print("設定裝置屬性失敗");
                      LogUtil.error(JSON.toJSONString(response));
                  }
      
              } catch (ClientException e) {
                  e.printStackTrace();
                  LogUtil.error("設定裝置屬性失敗!" + JSON.toJSONString(response));
              }
          }
    • 調用SetDevicesProperty大量設定裝置屬性值。
      /**
           * 大量設定裝置屬性。
           *
           * @param ProductKey:要設定屬性的裝置所隸屬的產品Key。
           * @param DeviceNames:要設定屬性的裝置名稱列表。
           * @param Items:要設定的屬性資訊,組成為key:value,資料格式為JSON String,必須傳入。
           *
           * @Des:描述。
           */
          public static void SetDevicesProperty(String InstanceId, String ProductKey, List<String> DeviceNames, String Items) {
              SetDevicesPropertyResponse response = new SetDevicesPropertyResponse();
              SetDevicesPropertyRequest request = new SetDevicesPropertyRequest();
              request.setDeviceNames(DeviceNames);
              request.setItems(Items);
              request.setProductKey(ProductKey);
              request.setIotInstanceId(InstanceId);
      
              try {
                  response = client.getAcsResponse(request);
      
                  if (response.getSuccess() != null && response.getSuccess()) {
                      LogUtil.print("大量設定裝置屬性成功");
                      LogUtil.print(JSON.toJSONString(response));
                  } else {
                      LogUtil.print("大量設定裝置屬性失敗");
                      LogUtil.error(JSON.toJSONString(response));
                  }
              } catch (ClientException e) {
                  e.printStackTrace();
                  LogUtil.error("大量設定裝置屬性失敗!" + JSON.toJSONString(response));
              }
          }
    • 調用InvokeThingService調用裝置服務。
           /**
           * @param Identifier:服務的Identifier,必須傳入。
           * @param Args:要啟用服務的入參資訊,必須傳入。
           */
          public static InvokeThingServiceResponse.Data InvokeThingService(String InstanceId, String IotId, String ProductKey, String DeviceName,
                                                                           String Identifier, String Args) {
              InvokeThingServiceResponse response =null;
              InvokeThingServiceRequest request = new InvokeThingServiceRequest();
              request.setArgs(Args);
              request.setDeviceName(DeviceName);
              request.setIotId(IotId);
              request.setIdentifier(Identifier);
              request.setProductKey(ProductKey);
              request.setIotInstanceId(InstanceId);
      
              try {
                  response = client.getAcsResponse(request);
      
                  if (response.getSuccess() != null && response.getSuccess()) {
                      LogUtil.print("服務執行成功");
                      LogUtil.print(JSON.toJSONString(response));
                  } else {
                      LogUtil.print("服務執行失敗");
                      LogUtil.error(JSON.toJSONString(response));
                  }
                  return response.getData();
      
              } catch (ClientException e) {
                  e.printStackTrace();
                  LogUtil.error("服務執行失敗!" + JSON.toJSONString(response));
              }
              return null;
          }
    • 調用InvokeThingsService批量調用裝置服務。
           /**
           * @param Identifier:服務的Identifier,必須傳入。
           * @param Args:要啟用服務的入參資訊,必須傳入。
           */
          public static void InvokeThingsService(String InstanceId, String IotId, String ProductKey, List<String> DeviceNames,
                                                 String Identifier, String Args) {
              InvokeThingsServiceResponse response =null;
              InvokeThingsServiceRequest request = new InvokeThingsServiceRequest();
              request.setArgs(Args);
              request.setIdentifier(Identifier);
              request.setDeviceNames(DeviceNames);
              request.setProductKey(ProductKey);
              request.setIotInstanceId(InstanceId);
      
              try {
                  response = client.getAcsResponse(request);
      
                  if (response.getSuccess() != null && response.getSuccess()) {
                      LogUtil.print("批量調用裝置服務成功");
                      LogUtil.print(JSON.toJSONString(response));
                  } else {
                      LogUtil.print("批量調用裝置服務失敗");
                      LogUtil.error(JSON.toJSONString(response));
                  }
      
              } catch (ClientException e) {
                  e.printStackTrace();
                  LogUtil.error("批量調用裝置服務失敗!" + JSON.toJSONString(response));
              }
          }

設定屬性和調用服務的請求樣本:

public static void main(String[] args) {
        /**上線裝置的裝置名稱和所屬產品的ProductKey。*/
        String deviceName = "2pxuAQB2I7wGPmqq***";
        String deviceProductkey = "a1QbjI2***";

        /**對於企業版執行個體和新版公用執行個體,設定InstanceId為具體執行個體ID值,您可在物聯網平台控制台的執行個體概覽頁面,查看當前執行個體的ID。
         *對於舊版公用執行個體,設定InstanceId為空白值""。
         */
        String InstanceId = "iot-***tl02";

        //1 設定裝置的屬性。
        SetDeviceProperty(InstanceId, null, deviceProductkey, deviceName,"{\"hue\":0}");
        //2 大量設定裝置屬性。
        List<String>  deviceNames = new ArrayList<>();
        deviceNames.add(deviceName);
        SetDevicesProperty(InstanceId, deviceProductkey, deviceNames, "{\"hue\":0}");
        //3 調用裝置的服務。
        InvokeThingService(InstanceId, null, deviceProductkey, deviceName, "ModifyVehicleInfo", "{}");
        //4 批量調用裝置的服務。
        List<String>  deviceNamesService = new ArrayList<>();
        deviceNamesService.add(deviceName);
        InvokeThingsService(InstanceId, null, deviceProductkey, deviceNamesService, "ModifyVehicleInfo", "{}");
    }

運行調試

裝置端SDK和雲端SDK配置完成後,運行各SDK。

查看結果:

  • 查看本地日誌。物模型通訊
  • 在物聯網平台控制台,對應裝置的裝置詳情頁面,單擊預設模組
    • 運行狀態頁簽下,查看裝置最後一次上報的屬性值和屬性資料記錄。
    • 事件管理頁簽下,查看裝置上報的事件記錄。
    • 服務調用頁簽下,查看雲端下發的服務調用記錄。
    物模型通訊