
# Java Demo使用说明
#### 概述
本文以Java语言为例，介绍通过MQTTS/MQTT协议接入平台，基于[平台接口](https://support.huaweicloud.com/api-iothub/iot_06_v5_3002.html)实现"属性上报"、"订阅接收命令"等功能。
![](https://support.huaweicloud.com/devg-iothub/public_sys-resources/note_3.0-zh-cn.png)
本文中使用的代码为样例代码，仅用于体验平台通信功能，如需进行商用，可以参考[资源获取](https://support.huaweicloud.com/devg-iothub/iot_02_1004.html)获取对应语言的IoT Device SDK进行集成。
#### 前提条件
- 已在[管理控制台](https://console.huaweicloud.com/iotdm/#/dm-portal/home)获取设备接入地址。获取地址的操作步骤，请参考[平台对接信息](https://support.huaweicloud.com/devg-iothub/iot_02_1004.html)。
- 已在[管理控制台](https://console.huaweicloud.com/iotdm/#/dm-portal/home)创建产品和设备。创建产品和设备的具体操作细节，请参考[创建产品](https://support.huaweicloud.com/usermanual-iothub/iot_01_0054.html)、[注册单个设备](https://support.huaweicloud.com/usermanual-iothub/iot_01_0031.html)或[批量注册设备](https://support.huaweicloud.com/usermanual-iothub/iot_01_0032.html)。
 
#### 准备工作
安装**IntelliJ IDEA**
1. 访问[IntelliJ IDEA官网](https://www.jetbrains.com/idea/)，选择合适系统的版本下载。（本文以windows 64-bit系统IntelliJ IDEA 2019.2.3 Ultimate为例）。
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0242224126.png "点击放大")
   
2. 下载完成后，运行安装文件，根据界面提示安装。
 
#### 导入代码样例
1. 下载[JAVA样例](https://developer.obs.cn-north-4.myhuaweicloud.com:443/manage/south/quickStart/quickStart(java).zip)。
2. 打开IDEA开发者工具，单击" Import Project"。 
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0242083727.png "点击放大")
   
   
3. 选择步骤[1]中下载的样例，然后根据界面提示，单击"next"。
   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0242083728.png "点击放大")
   
   
4. 完成代码导入。 
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0242083729.png)
   
   
 
#### 建立连接
设备或网关在接入物联网平台时首先需要和平台建立连接，从而将设备或网关与平台进行关联。开发者通过传入设备信息，将设备或网关连接到物联网平台。
1. 在建立连接之前，先修改以下参数：
   ```
   //IoT平台mqtt对接地址（要替换为设备所在的平台域名地址）
   static String serverIp = "xxx.myhuaweicloud.com";
   //注册设备时获得的deviceId,密钥（要替换为自己注册的设备ID与密钥）
   static String deviceId = "722cb****************";
   static String secret = "******";
   ```
   - serverIp为物联网平台的设备对接地址，可参考[平台对接信息](https://support.huaweicloud.com/devg-iothub/iot_02_1004.html)获取（获取的是域名信息，可通过在cmd命令框中执行"ping 域名"，获取IP地址）。
   
   - deviceId和secret为设备ID和密钥，在成功[注册设备](https://support.huaweicloud.com/usermanual-iothub/iot_01_0031.html)后获取。
    
2. 修改完[1]中的参数后就可使用MqttClient建立连接了。mqtt连接心跳时间的建议值是120秒，有[使用限制](https://support.huaweicloud.com/devg-iothub/iot_02_2200.html#ZH-CN_TOPIC_0246021145__section1565109112518)。
   ```
   MqttConnectOptions options = new MqttConnectOptions();
   options.setCleanSession(false);
   options.setKeepAliveInterval(120);  //心跳时间限定为30至1200秒
   options.setConnectionTimeout(5000);
   options.setAutomaticReconnect(true);
   options.setUserName(deviceId);
   options.setPassword(getPassword().toCharArray());
   client = new MqttAsyncClient(url, getClientId(), new MemoryPersistence());
   client.setCallback(callback);
   ```
   1883是mqtt非安全加密接入端口，8883是mqtts安全加密接入端口（使用SSL加载证书）。
   ```
   if (isSSL) {
       url = "ssl://" + serverIp + ":" + 8883; //mqtts连接
   } else {
       url = "tcp://" + serverIp + ":" + 1883; //mqtt连接
   }
   ```
   如果建立MQTTS连接，需要加载服务器端SSL证书，需要添加SocketFactory参数。DigiCertGlobalRootCA.jks在demo的resources目录下，是设备校验平台身份的证书，用于设备侧接入物联网平台登录鉴权使用，可以在资源获取中[下载证书文件](https://support.huaweicloud.com/devg-iothub/iot_02_1004.html#section3)。
   ```
   options.setSocketFactory(getOptionSocketFactory(MqttDemo.class.getClassLoader().getResource("DigiCertGlobalRootCA.jks").getPath()));
   ```
   
3. 调用client.connect(options, null, new IMqttActionListener())发起连接。连接时，需要向函数传入MqttConnectOptions连接参数。
   ```
   client.connect(options, null, new IMqttActionListener()
   ```
   
4. 在创建MqttConnectOptions连接参数时，调用options.setPassword()传入的密码会做一个加密。getPassword()为获取加密后的密钥。
   ```
   public static String getPassword() {
       return sha256_mac(secret, getTimeStamp());
   }
   /* 调用sha256算法进行哈希 */
   public static String sha256_mac(String message, String tStamp) {    
       String passWord = null;
       try {        
           Mac sha256_HMAC = Mac.getInstance("HmacSHA256");        
           SecretKeySpec secret_key = new SecretKeySpec(tStamp.getBytes(), "HmacSHA256");        
           sha256_HMAC.init(secret_key);byte[] bytes = sha256_HMAC.doFinal(message.getBytes());        
           passWord = byteArrayToHexString(bytes);    
       } catch (Exception e) {
           e.printStackTrace();    
       }
       return passWord;
   ```
   
5. 连接成功后，设备显示在线。
   图1设备列表-设备在线   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001950367902.png "点击放大")
   **注：如果连接失败，在onFailure函数中已实现退避重连，代码样例如下：**
   ```
   @Override
   public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
       System.out.println("Mqtt connect fail.");
       //退避重连
       int lowBound = (int) (defaultBackoff * 0.8);
       int highBound = (int) (defaultBackoff * 1.2);
       long randomBackOff = random.nextInt(highBound - lowBound);
       long backOffWithJitter = (int) (Math.pow(2.0, (double) retryTimes)) * (randomBackOff + lowBound);
       long waitTImeUntilNextRetry = (int) (minBackoff + backOffWithJitter) > maxBackoff ? maxBackoff : (minBackoff + backOffWithJitter);
       System.out.println("----  " + waitTImeUntilNextRetry);
       try {
           Thread.sleep(waitTImeUntilNextRetry);
           } catch (InterruptedException e) {
               System.out.println("sleep failed, the reason is" + e.getMessage().toString());
           }
           retryTimes++;
           MqttDemo.this.connect(true);
   }
   ```
   
 
#### 订阅接收命令
订阅某Topic的设备才能接收broker发布的关于该Topic的消息，关于平台预置Topic可参考[Topic定义](https://support.huaweicloud.com/api-iothub/iot_06_v5_3004.html)。详细接口信息请参考[命令下发](https://support.huaweicloud.com/api-iothub/iot_06_v5_3014.html)。
```
//订阅接收命令
client.subscribe(getCmdRequestTopic(), qosLevel, null, new IMqttActionListener();
```
getCmdRequestTopic()获取接收命令的Topic，向平台订阅该Topic的命令。
```
public static String getCmdRequestTopic() {
    return "$oc/devices/" + deviceId + "/sys/commands/#";
}
```
#### 属性上报
属性上报是指设备主动向平台上报自己的属性，更多信息请参考[设备属性上报](https://support.huaweicloud.com/api-iothub/iot_06_v5_3010.html)。
```
//上报json数据，注意serviceId要与产品模型中的定义对应
String jsonMsg = "{\"services\": [{\"service_id\": \"Temperature\",\"properties\": {\"value\": 57}},{\"service_id\": \"Battery\",\"properties\": {\"level\": 80}}]}";
MqttMessage message = new MqttMessage(jsonMsg.getBytes());
client.publish(getRreportTopic(), message, qosLevel, new IMqttActionListener();
```
消息体jsonMsg组装格式为JSON，其中service_id要与产品模型中的定义对应，properties是设备的属性，57为对应的属性值。event_time为可选项，为设备采集数据UTC时间，不填写默认使用系统时间。
设备或网关成功连接到物联网平台后，即可调用MqttClient.publish(String topic,MqttMessage message)向平台上报设备属性值。
getRreportTopic()即为获取上报数据的Topic。
```
public static String getRreportTopic() {
    return "$oc/devices/" + deviceId + "/sys/properties/report";
}
```
#### 查看上报数据
运行main方法成功启动后，即可在设备设备详情页面查看上报的设备属性数据。详细接口信息请参考[设备属性上报](https://support.huaweicloud.com/api-iothub/iot_06_v5_3010.html)。
图2查看上报数据-level   
![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001950370358.png "点击放大")
图3查看上报数据-temperature_value   
![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001950332868.png "点击放大")
![](https://support.huaweicloud.com/devg-iothub/public_sys-resources/note_3.0-zh-cn.png)
如果在"设备详情"页面没有最新上报数据，请确认设备上报的服务/属性和产品模型中的服务/属性一致。
#### 相关资源
您可以参考[MQTT接口](https://support.huaweicloud.com/api-iothub/iot_06_v5_3002.html)文档，把具备MQTT通信能力的设备接入物联网平台。您也可以[在线开发MQTT协议的智慧路灯](https://support.huaweicloud.com/bestpractice-iothub/iot_bp_00016.html)，快速验证是否可以与物联网平台服务交互发布或订阅消息。
![](https://support.huaweicloud.com/devg-iothub/public_sys-resources/note_3.0-zh-cn.png)
由于是同步命令需要端侧回复响应可[参考接口](https://support.huaweicloud.com/api-iothub/iot_06_v5_3014.html#section4)。
