物模型通信

设备与云端基于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。

查看结果:

  • 查看本地日志。物模型通信
  • 在物联网平台控制台,对应实例下设备的设备详情页面,单击默认模块
    • 运行状态页签下,查看设备最后一次上报的属性值和属性数据记录。
    • 事件管理页签下,查看设备上报的事件记录。
    • 服务调用页签下,查看云端下发的服务调用记录。
    物模型通信