
# MQTT over WebSocket 使用说明
#### 概述
本文以JavaScript为例，介绍基于WebSocket的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进行集成。
#### 使用限制
- MQTT over WebSocket只支持wss方式，需要使用和TLS直连一样的[根证书](https://support.huaweicloud.com/devg-iothub/iot_02_1004.html#ZH-CN_TOPIC_0187644975__section197481637133318)。
- MQTT over WebSocket默认使用的端口为443，企业版实例可以根据业务场景定制。
- MQTT over WebSocket的接口同[MQTT接口](https://support.huaweicloud.com/api-iothub/iot_06_v5_3002.html)一致。
 
#### 前提条件
- 已在[管理控制台](https://console.huaweicloud.com/iotdm/#/dm-portal/home)获取设备接入地址。获取地址的操作步骤，请参考[平台对接信息](https://support.huaweicloud.com/devg-iothub/iot_02_1004.html#ZH-CN_TOPIC_0187644975__section436212919379)。
- 已在[管理控制台](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)。
 
#### 导入代码样例
1. 下载[quickStart(websocket).zip](https://obs-pipeline.obs.cn-north-4.myhuaweicloud.com/sdkDeploy/quickStart/quickStart(websocket) .zip)样例，并解压。
2. 修改Demo里的关键工程配置参数。其中MqttOverWebsocketDemo.html需要配置host地址、设备ID和设备密钥，用于启动Demo时连接平台。 
   - host地址：即域名，请参考[平台对接信息](https://support.huaweicloud.com/devg-iothub/iot_02_1004.html#ZH-CN_TOPIC_0187644975__section436212919379)获取；
   
   - 设备ID和设备密钥：在物联网平台[注册设备](https://support.huaweicloud.com/usermanual-iothub/iot_01_0031.html)或调用[创建设备](https://support.huaweicloud.com/api-iothub/iot_06_v5_0046.html)接口后获取。
   
   
   ```
   var host = '****'; //IoT平台mqtt对接地址
       var deviceId = '****'; //请填写在平台注册的设备ID
       var secret = '****'; //请填写在平台注册的设备密钥
   ```
   
   
 
#### 程序启动
设备或网关在接入物联网平台时首先需要和平台建立连接，从而将设备或网关与平台进行关联。开发者通过传入设备信息，将设备连接到物联网平台。
1. 找到MqttOverWebsocketDemo.html源码目录，修改[关键工程配置参数](https://support.huaweicloud.com/devg-iothub/iot_02_2133.html#ZH-CN_TOPIC_0232966960__li2634192705710)后用浏览器打开Demo，启动程序前，在平台界面上显示设备状态是离线。
   
   图1设备列表-设备离线   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001981569133.png "点击放大")
   启动程序后，按F12进入调试界面console栏中日志显示如下：
   图2日志显示连接成功   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001163469689.png "点击放大")
   平台上显示设备状态变为在线
   图3设备列表-设备在线   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001950367902.png "点击放大")
   ![](https://support.huaweicloud.com/devg-iothub/public_sys-resources/note_3.0-zh-cn.png)
   如果连接失败，需要在重连回调函数中实现退避重连，代码样例如下：
   ```
   function reConnect() {
           log("reconnect is starting");
           //退避重连
           let lowBound = Number(defaultBackoff) * Number(0.8);
           let highBound = Number(defaultBackoff) * Number(1.2);
           let randomBackOff = parseInt(Math.random() * (highBound - lowBound + 1), 10);
           let backOffWithJitter = (Math.pow(2.0, retryTimes)) * (randomBackOff + lowBound);
           let waitTImeUtilNextRetry = (minBackoff + backOffWithJitter) > maxBackoff ? maxBackoff : (minBackoff + backOffWithJitter);
           log("wait time: " + waitTImeUtilNextRetry);
           setTimeout(()=> { client.connect(options); }, waitTImeUtilNextRetry);
           retryTimes++;
       }
   ```
   
   
2. 订阅某Topic的设备才能接收平台发布的关于该Topic的消息，关于平台预置Topic可参考[Topic定义](https://support.huaweicloud.com/api-iothub/iot_06_v5_3004.html)。此Demo调用subScribeTopic方法进行订阅Topic，订阅成功后等待平台命令下发：
   
   ```
   //订阅接收命令topic
       function subScribeTopic() {
           log('subscribe topic ' + getCmdRequestTopic());
           client.subscribe(getCmdRequestTopic());
       }
   ```
   
   
3. 发布Topic是指设备主动向平台上报自己的属性或消息，详细见[设备属性上报接口](https://support.huaweicloud.com/api-iothub/iot_06_v5_3010.html)文档。连接成功后，调用publishMessage方法进行属性上报：
   
   ```
   //上报json数据，注意serviceId要与Profile中的定义对应
   function publishMessage() {
       var jsonMsg = propertiesReport;
       log("publish message topic is " + getReportTopic());
       log("publish message is " + jsonMsg);
       client.publish(getReportTopic(), jsonMsg);
       log("publish message successful");
   }
   ```
   上报属性的json：
   ```
   var propertiesReportJson = {'services':[{'properties':{'alarm':1,'temperature':12.670784,'humidity':18.37673,'smokeConcentration':19.97906},'service_id':'smokeDetector','event_time':null}]};
   ```
   浏览器调试界面的console栏中显示如下：
   图4日志显示上报数据成功   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001117110254.png "点击放大")
   属性上报成功，平台界面如下：
   图5查看上报数据-WSDemo_smokeDetector   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001950483004.png "点击放大")
   ![](https://support.huaweicloud.com/devg-iothub/public_sys-resources/note_3.0-zh-cn.png)
   如果在"设备详情"页面没有最新上报数据，请修改产品模型中服务和属性的内容，确保设备上报的服务/属性和产品模型中的服务/属性一致，或者进入"产品 \> 基本信息"页面，删除所有服务。
   
   
 
#### 接收下发命令
在Demo中提供了接收平台下发命令的功能，在MQTT建链完成并成功订阅Topic后，可以在[管理控制台](https://console.huaweicloud.com/iotdm/#/dm-portal/home)设备详情中命令下发或[使用应用侧Demo](https://support.huaweicloud.com/devg-iothub/iot_02_9994.html)对该设备ID进行命令下发。下发成功后，在Demo中接收到平台下发给设备的命令。
例如下发参数名为smokeDetector: SILENCE，参数值为1的命令。
图6命令下发-SILENCE_1   
![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001981685193.png "点击放大")
命令下发成功后，Demo收到平台下发的命令，浏览器调试界面的console栏显示如下：
图7显示   
![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001117272582.png "点击放大")
![](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)。
#### 相关最佳实践
[路灯通过微信小程序接入到平台](https://support.huaweicloud.com/bestpractice-iothub/iot_bp_0050.html)
