08.QCloud_IoTHub_Quick_Start.md 19.7 KB
Newer Older
S
supowang 已提交
1 2 3 4 5 6
# TencentOS tiny端云对接开发指南(IoTHub)

| Revision | Date      | Description |
| -------- | --------- | ----------- |
| 1.0      | 2019-1-15 | 文档初版    |
| 2.0      | 2019-8-13 | 文档V2.0    |
7
| 3.0      | 2020-02-26| 文档V3.0    |
S
supowang 已提交
8 9 10 11 12 13 14 15

概览
----

腾讯物联网通信(IoT Hub)服务,旨在提供一个安全、稳定、高效的连接平台,帮助开发者低成本、快速地实现“设备-设备”、“设备-用户应用”、“设备-云服务”之间可靠、高并发的数据通信。也就是说,腾讯物联网通信可以实现设备之间的互动、设备的数据上报和配置下发,还可以基于规则引擎和腾讯云产品打通,方便快捷的实现海量设备数据的存储、计算以及智能分析。总之,基于腾讯物联网通信,开发者可以低成本实现“设备-数据-应用-云服务”的连接,快速搭建物联网应用平台。

**腾讯云物联网通信产品架构**

D
daishengdong 已提交
16
![](image/iothub_guide/qcloud_arch.png)
S
supowang 已提交
17 18 19 20 21 22 23

在上图所示的架构中, 本文只讨论"用户设备"和腾讯云的对接. 这上图中可以看到, "用户设备"和腾讯云之间是基于**MQTT**协议或是**CoAP**协议进行通信的. 因此, 在"用户设备"上, 需要包含连接SDK或是实现了MQTT或CoAP协议的代码. 本文讲述MQTT连接方法, CoAP协议类似.

**MQTT简介**

物联网 (IoT) 设备必须连接互联网. 通过连接到互联网, 设备就能相互协作, 以及与后端服务协同工作. 互联网的基础网络协议是 TCP/IP. MQTT(消息队列遥测传输)是基于 TCP/IP 协议栈而构建的, 已成为 IoT 通信的标准. MQTT本身是个轻量级的协议, 可以在硬件受限设备上实现. 同时, MQTT协议支持在各方之间异步通信的消息协议, 异步消息协议在空间和时间上将消息发送者与接收者分离, 因此可以在不可靠的网络环境中进行扩展. MQTT的灵活性使得为 IoT 设备和服务的多样化应用场景提供支持成为可能.

D
daishengdong 已提交
24
![](image/iothub_guide/mqtt_client_broker.png)
S
supowang 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38

MQTT协议基于发布(Publish)和订阅(Subscribe)模型. 在网络中定义了两种实体类型: **消息代理端(Broker)****客户端(Client)**, 代理是一个服务器, 它从客户端接收所有消息, 然后将这些消息路由到相关的目标客户端. 客户端是能够与代理交互来发送和接收消息的任何事物. 客户端可以是现场的 IoT 传感器, 或者是数据中心内处理 IoT 数据的应用程序.

Client和Broker之间的发布和订阅是根据主题(Topic)来进行的, 不同的客户端可以向不同的主题发布消息, 设备只有在订阅了某个主题后, 才能收到相应主题的消息.



云端设置
--------

云端设置主要包含了, 创建新产品, 创建新设备

登录腾讯云, 搜索"云产品"下的"物联网通信"产品, 或直接访问 https://console.cloud.tencent.com/iotcloud

D
daishengdong 已提交
39
![](image/iothub_guide/login_iotcloud.png)
S
supowang 已提交
40 41 42 43 44



**创建新产品**

D
daishengdong 已提交
45
![](image/iothub_guide/create_new_product.png)
S
supowang 已提交
46

D
daishengdong 已提交
47
![](image/iothub_guide/add_prodcut.png)
S
supowang 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60

在"添加新产品"的时候, 注意选择. 产品类型选择**普通产品**, 产品名称随意, 认证方式选择**密钥认证**, 数据格式选择**自定义**.

> 关于认证方式和数据格式的选择解释
>
> 认证方式默认的是证书认证, 数据格式默认的是json格式.
>
> 对于认证方式, 指定了设备通过何种方式和云端进行双向认证. 默认的证书方式相对于密钥认证安全性高一点, 但是问题在于证书方式需要在嵌入式设备端存储证书同时实现证书的相关处理, 对设备的RAM和ROM要求较高, 相对而言, 密钥认证的方式资源占用量就小点, 由于我们主要支持的设备都是小型嵌入式设备, 因此选用密钥认证.
>
> 数据格式指的是设备和云端进行数据交互时候使用的格式, json格式为文本字符串, 可读性高, 并且便于解析, 对于功能复杂的设备交互而已比较理想, 但是对于小型设备或是定制设备, 数据单一, 或是有自定义的格式(二进制或是文本), 这种时候, 用自定义的数据格式, 一方面节约流量, 另一方面比较灵活. 

注: 这里的数据格式选择会影响之后腾讯云"规则引擎"组件的设置.

D
daishengdong 已提交
61
![](image/iothub_guide/product_info.png)
S
supowang 已提交
62 63 64 65 66 67 68

新建完产品后, 会获得一个平台分配的**productID**.



**创建新设备**

D
daishengdong 已提交
69
![](image/iothub_guide/new_device.png)
S
supowang 已提交
70

D
daishengdong 已提交
71
![](image/iothub_guide/add_dev.png)
S
supowang 已提交
72 73 74

设置的时候只需要设置设备名称即可, 由于我们在创建产品的时候, 认证方式选择了密钥认证, 因此在创建设备的时候将会提供设备对应的密钥, 这里选择默认的"使用物联通通信提供的密钥"即可.

D
daishengdong 已提交
75
![](image/iothub_guide/add_dev_done.png)
S
supowang 已提交
76 77 78 79 80

添加完设备后, 会告知设备对应的密钥. 该密钥将会用于之后设备与平台通信时的认证.

为了实现设备间的通信, 我们还需要创建第二个设备, 操作同上, 不妨将其命名为"dev2".

D
daishengdong 已提交
81
![](image/iothub_guide/dev_list.png)
S
supowang 已提交
82 83 84 85 86 87 88 89 90

此时, 在产品"my_product"下面, 有2个我们添加的设备, 分别为"dev1"和"dev2".



**Topic设置**

我们知道, 设备通过MQTT协议进行通信, 是基于发布(publish)和订阅(subscribe)相关的话题(topic)来进行的, 因此, 还需要在云端对话题进行设置.

D
daishengdong 已提交
91
![](image/iothub_guide/topic_list.png)
S
supowang 已提交
92 93 94

我们可以在"权限列表"中看到Topic对应的操作权限, 此处还可以添加新的Topic.

S
Supowang1989 已提交
95
在这里, 我们可以看到, 平台默认配置了三类的Topic, 用于执行发布和订阅. 这里之所以是三类而不是三个, 是因为Topic里使用了变量. 这里的`25KCIUIR1G`实际上是productID; `${deviceName}`为平台设置的变量, 即设备名; `control``data`以及`event`为Topic名字. 所以, 在我们创建了2个设备dev1和dev2的情况下, 在my_product产品下, 即存在6个Topic, 分别为:
S
supowang 已提交
96

S
Supowang1989 已提交
97 98 99 100 101 102
- 25KCIUIR1G/dev1/control 订阅权限
- 25KCIUIR1G/dev1/data   发布和订阅权限
- 25KCIUIR1G/dev1/event 发布权限
- 25KCIUIR1G/dev2/control 订阅权限
- 25KCIUIR1G/dev2/data   发布和订阅权限
- 25KCIUIR1G/dev2/event 发布权限
S
supowang 已提交
103 104 105 106 107 108 109

这里默认的Topic已经足够我们使用, 不需要额外添加Topic和权限了.

> MQTT的Topic本身是一个普通的字符串, 但是可以由多个层级组成, 根据`/`来划分. 这种分层的Topic结构使得主题的过滤和匹配变得相对灵活.
>
> 多层通配符"#"
>
S
Supowang1989 已提交
110
> 必须位于最后一个字符, 匹配多层级. 例如对于`25KCIUIR1G/#`, 将会匹配`25KCIUIR1G/dev1`, `25KCIUIR1G/dev2`, `25KCIUIR1G/dev1/control`, `25KCIUIR1G/dev1/event`, `25KCIUIR1G/dev2/control`和`25KCIUIR1G/dev2/event`主题.
S
supowang 已提交
111 112 113 114 115
>
> 单层通配符"+"
>
> 匹配单个层级, 在主题的任何层级都可以使用, 包括第一个层级和最后一个层级.
>
S
Supowang1989 已提交
116
> 例如, 对于`25KCIUIR1G/+/event`, 将会匹配`25KCIUIR1G/dev1/event`和`25KCIUIR1G/dev2/event`.
S
supowang 已提交
117 118 119 120 121 122 123 124 125



**设置规则引擎**

规则引擎本身不属于MQTT协议的范畴, 但是平台侧出于安全角度考虑添加了规则引擎, 实现了Topic之间的转发操作, 我们需要合理的设置规则引擎才能实现多个设备之间的数据收发, 由于理解起来比较复杂, 我们这里简要讲解下为什么需要规则引擎, 规则引擎的作用, 如何设置规则引擎.

1. 为什么需要规则引擎

S
Supowang1989 已提交
126
   在上节的Topic中, 我们知道, 在平台侧, 对于不同的Topic, 规定了不同的权限, 例如, 对于`25KCIUIR1G/dev1/event`这个Topic, 只具有发布权限, 而对于`25KCIUIR1G/dev1/control`这个Topic, 只具有订阅权限. 对于设备dev1, 很自然的, 会朝`25KCIUIR1G/dev1/event`这个Topic发送数据, 并且订阅`25KCIUIR1G/dev1/control`这个Topic的消息. 但是这里就会涉及到, event的数据最后到哪去, control的数据从哪里来的问题.
S
supowang 已提交
127

S
Supowang1989 已提交
128
   在本文的例子中, 我们希望dev1和dev2发生交互, 即相互收发消息. 由于MQTT是基于Topic的发布订阅机制, 因此, dev1想要获得dev2的数据, 直觉上, 需要订阅dev2发布消息的那个Topic. 假定dev2朝`25KCIUIR1G/dev2/event`Topic上发送数据, 那么dev1想要获得dev2发布的消息, 最直接的办法是订阅同样的Topic, 即`25KCIUIR1G/dev2/event`, 但是这里存在几个问题, 首先, event Topic只具有发布权限, 没有订阅权限, 其次, **在平台侧, 规定了, 不允许跨设备发布或是订阅Topic**, 也就是说, 对于dev1, 只能看到或只允许访问`25KCIUIR1G/dev1`这个Topic以及其下属的Topic, 不能访问`25KCIUIR1G/dev2`及其下属Topic.
S
supowang 已提交
129 130 131 132 133 134 135

   > 平台侧添加不允许跨设备访问Topic的规则虽然不直观, 但却是合理的. 如果不添加这条限制, 那么一个设备可以不加限制的订阅同一个产品下所有其他设备的Topic, 获取其上报的消息, 这存在潜在的安全漏洞.

2. 规则引擎的作用

   因为不允许直接跨设备访问Topic, 所以需要依靠"规则引擎"来手动添加规则, 将指定的Topic消息转发到另一个Topic上, 实现不同设备之间的通信.

D
daishengdong 已提交
136
   ![](image/iothub_guide/rule_engine.png)
S
supowang 已提交
137

S
Supowang1989 已提交
138
   上图介绍了规则引擎的主要作用"republish", 即将一个Topic下的消息republish到另一个Topic下. 从图中我们可以看到, (产品ID以您实际的ID为准)规则引擎将`25KCIUIR1G/dev2/event`的消息republish到了`25KCIUIR1G/dev1/control`下. 将`25KCIUIR1G/dev1/event`的消息republish到了`25KCIUIR1G/dev2/control`下.
S
supowang 已提交
139

S
Supowang1989 已提交
140
   这样, 对于dev1而言, 只需要订阅`25KCIUIR1G/dev1/control`就可以接收来自`25KCIUIR1G/dev2/event`的消息了. dev2同理.
S
supowang 已提交
141 142 143

3. 设置规则引擎

D
daishengdong 已提交
144
   ![](image/iothub_guide/new_rule.png)
S
supowang 已提交
145 146 147

   在物联网通信界面选择"规则引擎"--"新建规则", 随意指定一个规则名称, 我们这里不妨设置为"1to2".

D
daishengdong 已提交
148
   ![](image/iothub_guide/rule_info.png)
S
supowang 已提交
149 150 151

   这里, 我们看到规则的详细设置信息, 主要包括"筛选数据"和"行为操作". "筛选数据"针对指定Topic接收到的消息内容进行进一步的筛选, 比如匹配消息中的字段来决定是否执行之后的设置的"行为操作". 而"行为操作"则是指定对通过匹配的消息进行何种操作, 主要的操作有"数据转发到另一个Topic(Republish)", "转发到第三方服务(Forward)"以及转发到腾讯云各个对应组件中.

D
daishengdong 已提交
152
   ![](image/iothub_guide/rule_set.png)
S
supowang 已提交
153

S
Supowang1989 已提交
154
   上图是设置好的规则, 这里, 我们将"筛选数据"部分的筛选字段设置为`*`, 筛选的Topic为`25KCIUIR1G/dev1/event`, 条件设置为空, 即不筛选数据, 全部匹配. 然后, 执行的操作是将数据转发到`25KCIUIR1G/dev2/control`, 设置完这条规则, 就实现了dev2通过订阅control就能收到dev1发送到event的数据.
S
supowang 已提交
155 156 157 158 159 160 161

   > 关于"筛选数据"的设定
   >
   > 由于我们在新建产品, 设置数据格式的时候选择了自定义数据格式, 在自定义数据格式的情况下, 当前平台将其当做二进制流来处理, 也就无法通过匹配字段进行数据筛选.
   >
   > 如果在进行产品的时候, 使用数据格式是json, 那么此处就可以根据json中的字段进行SQL的匹配和筛选.

S
Supowang1989 已提交
162
   同理, 我们再设置新的一个规则"2to1", 实现`25KCIUIR1G/dev2/event``25KCIUIR1G/dev1/control`的转发.
S
supowang 已提交
163

D
daishengdong 已提交
164
   ![](image/iothub_guide/rule_set_2to1.png)
S
supowang 已提交
165

166
   规则引擎都设置好后,记得点启用按钮,这样, 在平台侧dev1到dev2的双向数据通路就打通了.
S
supowang 已提交
167 168 169 170 171 172 173 174 175

**云日志和消息队列CMQ**

在平台侧都设置好后, 我们在之后的测试过程或是通信过程中, 往往还需要查看平台是否收到了设备发送上来的消息, 对消息执行了哪些操作, 消息的具体内容(payload)是什么. 腾讯云提供了物联网通信产品的"云日志"功能和腾讯云组件"消息队列CMQ".

云日志

可以在产品列表下找到"云日志", 点击搜索即可显示对应的行为日志

D
daishengdong 已提交
176
![](image/iothub_guide/log_search.png)
S
supowang 已提交
177 178 179

参考日志如下, 可以看到日志记录了设备的连接, 连接断开, 发布, 订阅等行为, 也记录了规则引擎的操作, 还有CMQ队列的一些行为日志. 但是关于设备发布的消息内容, 在云日志中无法查看, 需要借助消息队列CMQ.

D
daishengdong 已提交
180
![](image/iothub_guide/log.png)
S
supowang 已提交
181 182 183 184 185

消息队列CMQ

可以在产品列表中找到"消息队列"选项, 设置队列所想要接收的消息类型后保存配置, 即可将平台侧收到的设备消息额外发送到腾讯云消息队列CMQ组件中.

D
daishengdong 已提交
186
![](image/iothub_guide/cmq.png)
S
supowang 已提交
187 188 189

设置完消息队列后可以在"云产品"中搜索CMQ, 即可找到对应的消息队列, 点击"开始接收消息" 接收消息队列中的内容, 参考如下

D
daishengdong 已提交
190
![](image/iothub_guide/cmq_info.png)
S
supowang 已提交
191 192 193 194 195 196 197 198 199 200

其中可以看到有些消息带有"PayloadLen"和"Playload"字段, 即为具体的消息内容.

> 在密钥认证下, 消息的内容(payload)是经过base64编码的, 所以在平台侧看到的数据类似乱码实际上是经过编码后的结果, 想要查看具体的内容, 可以在linux下, `echo <payload> | base64 --decode`.

设备终端设置
------------

在前文中我们提到, 设备终端跟腾讯云之间的通信采用的是MQTT协议, 而MQTT协议需要消息代理端和客户端相互配合, 因此, 我们在终端设备上, 需要**实现一个MQTT Client**. 腾讯云上支持的MQTT协议和标准协议区别不大, 可以在[MQTT协议说明](https://cloud.tencent.com/document/product/634/14065)查看具体区别. 因此, 技术上来说, 设备终端只要实现了标准的MQTT客户端, 均可以跟腾讯云正常通信.

S
Supowang1989 已提交
201
在本节中, 我们介绍如何使用腾讯TencentOS tiny与腾讯云通过MQTT进行通信.
S
supowang 已提交
202

203
TencentOS Tiny 集成了对MQTT和腾讯云的支持, 开发者只需要通过简单的设置即可实现与腾讯云的通信, 整体步骤主要包含:
S
supowang 已提交
204 205 206 207 208 209 210 211

- 项目工程中添加MQTT组件相关文件
- 适配AT HAL层串口及网络接口函数
- 执行脚本生成MQTT配置头文件
- 调用OS提供的接口完成和腾讯云的对接

**项目工程中添加MQTT组件相关文件**

212
在工程添加hal、at、devices、和mqtt client源码, 可以参考TencentOS-tiny\board\TencentOS_tiny_EVB_MX_Plus\KEIL\mqttclient工程
S
supowang 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236



**适配AT HAL层串口及网络接口函数**

上层MQTT的操作最终都会转为为对底层通信设备的socket操作, OS集成了sal_module_wrapper层, 但是由于各个开发板硬件不同, 因此需要对sal_module_wrapper进行适配. 适配过程的核心数据结构为`sal_module_t`, 在`TencentOS_tiny\net\sal_module_wrapper\sal_module_wrapper.h`文件中定义:

```c
typedef struct sal_module_st{
    int (*init)(void);
    int (*get_local_mac)(char *mac);
    int (*get_local_ip)(char *ip, char *gw, char *mask);
    int (*parse_domain)(const char *host_name, char *host_ip, size_t host_ip_len);
    int (*connect)(const char *ip, const char *port, sal_proto_t proto);
    int (*send)(int sock, const void *buf, size_t len);
    int (*recv_timeout)(int sock, void *buf, size_t len, uint32_t timeout);
    int (*recv)(int sock, void *buf, size_t len);
    int (*sendto)(int sock, char *ip, char *port, const void *buf, size_t len);
    int (*recvfrom)(int sock, char *ip, char *port, void *buf, size_t len);
    int (*recvfrom_timeout)(int sock, char *ip, char *port, void *buf, size_t len, uint32_t timeout);
    int (*close)(int sock);
}sal_module_t;
```

zhaoyanbai's avatar
zhaoyanbai 已提交
237
在使用的时候, 并不需要全部实现, 只需实现下列几个核心的接口即可:
S
supowang 已提交
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

```c
sal_module_t sal_module_esp8266 = {
    .init               = esp8266_init,
    .connect            = esp8266_connect,
    .send               = esp8266_send,
    .recv_timeout       = esp8266_recv_timeout,
    .recv               = esp8266_recv,
    .sendto             = esp8266_sendto,
    .recvfrom           = esp8266_recvfrom,
    .recvfrom_timeout   = esp8266_recvfrom_timeout,
    .close              = esp8266_close,
    .parse_domain       = esp8266_parse_domain,
};
```

这里接口对应的`esp8266_xxx`函数需要开发者根据硬件上具有的通信模组进行相应的适配.

该结构填充完后, 需要在使用MQTT之前, 调用一下初始化接口注册串口和网络API函数:

```c
esp8266_sal_init(hal_uart_port_t uart_port);
```

262
**修改MQTT配置头文件**
S
supowang 已提交
263 264 265 266 267

从之前介绍腾讯云端配置的章节中可以知道, 在MQTT客户端, 所需要的核心信息只包含:

- Product ID
- Device Name
S
Supowang1989 已提交
268 269 270 271
- Device Password
- Client id
- mqtt username
- mqtt password
S
supowang 已提交
272

S
Supowang1989 已提交
273 274
![](image/iothub_guide/dev_info.png)

275
开发者在终端节点开发过程中, 可以自行修改MQTT配置参数
S
supowang 已提交
276 277

```shell
278 279 280 281 282 283 284
#define IOTHUB_MQTT_IP          "111.230.189.156"
#define IOTHUB_MQTT_PORT        "1883"
#define IOTHUB_MQTT_CLIENT_ID   "KHHIXM0JJ5dev001"
#define IOTHUB_MQTT_USERNAME    "KHHIXM0JJ5dev001;12010126;9K3WO;1647628324"
#define IOTHUB_MQTT_PASSWD      "53696f22a061ed2524b1de185815ad2fcae7739afd3f395cb6131521da7f0bb7;hmacsha256"
#define IOTHUB_MQTT_PUB_TOPIC   "KHHIXM0JJ5/dev001/data"
#define IOTHUB_MQTT_SUB_TOPIC   "KHHIXM0JJ5/dev001/control"
S
supowang 已提交
285 286
```

S
Supowang1989 已提交
287
如上所示, 需要腾讯云设备信息自行修改`Product ID`, `Device Name``Password``MQTT_USR_NAME``MQTT_PASSWORD``MQTT_SUBSCRIBE_TOPIC``MQTT_PUBLISH_TOPIC`,订阅/发布的topic, 如果采用默认的control和event如图即可, 也可自行设置.  开发者将其放置到自己的工程目录下任意位置并在工程中添加头文件引用即可.
S
supowang 已提交
288 289 290 291 292 293

**调用TencentOS tiny提供的接口完成和腾讯云的对接**

以下是与腾讯云对接并收发信息的例程:

```c
294 295 296 297 298 299 300 301 302 303
/* Tencent IoThub Device Info */
#define IOTHUB_MQTT_IP          "111.230.189.156"
#define IOTHUB_MQTT_PORT        "1883"
#define IOTHUB_MQTT_CLIENT_ID   "KHHIXM0JJ5dev001"
#define IOTHUB_MQTT_USERNAME    "KHHIXM0JJ5dev001;12010126;9K3WO;1647628324"
#define IOTHUB_MQTT_PASSWD      "53696f22a061ed2524b1de185815ad2fcae7739afd3f395cb6131521da7f0bb7;hmacsha256"
#define IOTHUB_MQTT_PUB_TOPIC   "KHHIXM0JJ5/dev001/data"
#define IOTHUB_MQTT_SUB_TOPIC   "KHHIXM0JJ5/dev001/control"

static void tos_topic_handler(void* client, message_data_t* msg)
S
supowang 已提交
304
{
305 306 307 308 309 310
    (void) client;
    MQTT_LOG_I("-----------------------------------------------------------------------------------");
    MQTT_LOG_I("%s:%d %s()...\ntopic: %s, qos: %d. \nmessage:\n\t%s\n", __FILE__, __LINE__, __FUNCTION__, 
            msg->topic_name, msg->message->qos, (char*)msg->message->payload);
    MQTT_LOG_I("-----------------------------------------------------------------------------------\n");
}
S
supowang 已提交
311

312 313 314 315 316 317 318 319 320 321 322 323 324

void mqttclient_task(void)
{
    int error;

    char buf[100] = { 0 };
    
    mqtt_client_t *client = NULL;
    
    mqtt_message_t msg;
    
    memset(&msg, 0, sizeof(msg));
    
S
supowang 已提交
325 326
#ifdef USE_ESP8266 
    esp8266_sal_init(HAL_UART_PORT_0);
327
    esp8266_join_ap("Mculover666", "mculover666");
S
supowang 已提交
328 329 330 331 332 333
#endif

#ifdef USE_NB_BC35
    int bc35_28_95_sal_init(hal_uart_port_t uart_port);
    bc35_28_95_sal_init(HAL_UART_PORT_0);
#endif
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    
#ifdef USE_EC600S
    ec600s_sal_init(HAL_UART_PORT_0);
#endif
    
    
    mqtt_log_init();

    client = mqtt_lease();
    
    mqtt_set_port(client, IOTHUB_MQTT_PORT);
    mqtt_set_host(client, IOTHUB_MQTT_IP);
    mqtt_set_client_id(client, IOTHUB_MQTT_CLIENT_ID);
    mqtt_set_user_name(client, IOTHUB_MQTT_USERNAME);
    mqtt_set_password(client, IOTHUB_MQTT_PASSWD);
    mqtt_set_clean_session(client, 1);

    error = mqtt_connect(client);
    
    MQTT_LOG_D("mqtt connect error is %#x", error);
    
    mqtt_subscribe(client, IOTHUB_MQTT_SUB_TOPIC, QOS0, tos_topic_handler);
    
    MQTT_LOG_D("mqtt subscribe error is %#x", error);
    
    memset(&msg, 0, sizeof(msg));

    for (;;) {
        
        sprintf(buf, "welcome to mqttclient, this is a publish test, a rand number: %d ...", random_number());
        
        msg.qos = QOS0;
        msg.payload = (void *) buf;
        
        error = mqtt_publish(client, IOTHUB_MQTT_PUB_TOPIC, &msg);

        tos_task_delay(4000); 
S
supowang 已提交
371
    }
372 373
}

S
supowang 已提交
374

375 376 377
void application_entry(void *arg)
{
    mqttclient_task();
S
supowang 已提交
378
    while (1) {
379 380
        printf("This is a mqtt demo!\r\n");
        tos_task_delay(1000);
S
supowang 已提交
381 382 383
    }
}
```