1 /** 2 * @file aiot_mqtt_api.h 3 * @brief MQTT模块头文件, 提供用MQTT协议连接阿里云物联网平台的能力 4 * @date 2019-12-27 5 * 6 * @copyright Copyright (C) 2015-2018 Alibaba Group Holding Limited 7 * 8 * @details 9 * 10 * MQTT模块用于建立与阿里云物联网平台的连接, API使用流程如下: 11 * 12 * 1. 调用 @ref aiot_mqtt_init 初始化MQTT会话, 获取会话句柄 13 * 14 * 2. 调用 @ref aiot_mqtt_setopt 配置MQTT会话的参数, 常用配置项见 @ref aiot_mqtt_setopt 的说明 15 * 16 * 3. 调用 @ref aiot_mqtt_connect 建立与阿里云物联网平台的连接 17 * 18 * 4. 启动一个线程, 线程中间歇性调用 @ref aiot_mqtt_process 处理心跳和QoS1的消息 19 * 20 * 5. 启动一个线程, 线程中持续调用 @ref aiot_mqtt_recv 接收网络上的MQTT报文 21 * 22 * + 当接收到一条报文时, 按以下顺序检查当前MQTT会话的参数, 当满足某条的描述时, 会通过对应的回调函数进行通知, 并停止检查 23 * 24 * + 检查收到的报文topic是否已经通过 @ref aiot_mqtt_setopt 的 @ref AIOT_MQTTOPT_APPEND_TOPIC_MAP 参数配置回调函数 25 * 26 * + 检查收到的报文topic是否已经通过 @ref aiot_mqtt_sub API配置回调函数 27 * 28 * + 检查是否通过 @ref aiot_mqtt_setopt 的 @ref AIOT_MQTTOPT_RECV_HANDLER 参数配置默认回调函数 29 * 30 * 6. 经过以上步骤后, MQTT连接已建立并能保持与物联网平台的连接, 接下来按自己的场景用 @ref aiot_mqtt_sub 和 @ref aiot_mqtt_pub 等API实现业务逻辑即可 31 * 32 */ 33 34 #ifndef _AIOT_MQTT_API_H_ 35 #define _AIOT_MQTT_API_H_ 36 37 #if defined(__cplusplus) 38 extern "C" { 39 #endif 40 41 #include <stdint.h> 42 43 /** 44 * @brief MQTT报文类型 45 * 46 * @details 47 * 48 * 传入@ref aiot_mqtt_recv_handler_t 的MQTT报文类型 49 */ 50 typedef enum { 51 /** 52 * @brief MQTT PUBLISH报文 53 */ 54 AIOT_MQTTRECV_PUB, 55 56 /** 57 * @brief MQTT PINGRESP报文 58 */ 59 AIOT_MQTTRECV_HEARTBEAT_RESPONSE, 60 61 /** 62 * @brief MQTT SUBACK报文 63 */ 64 AIOT_MQTTRECV_SUB_ACK, 65 66 /** 67 * @brief MQTT UNSUB报文 68 */ 69 AIOT_MQTTRECV_UNSUB_ACK, 70 71 /** 72 * @brief MQTT PUBACK报文 73 */ 74 AIOT_MQTTRECV_PUB_ACK, 75 76 /** 77 * @brief MQTT CONACK报文 78 */ 79 AIOT_MQTTRECV_CON_ACK, 80 81 /** 82 * @brief MQTT SERVER DISCONNECT报文 83 */ 84 AIOT_MQTTRECV_DISCONNECT, 85 } aiot_mqtt_recv_type_t; 86 87 88 /** 89 * @brief MQTT协议版本 90 * 91 * @details 92 * 93 * 传入@ref aiot_mqtt_setopt 的MQTT协议版本号 94 */ 95 96 typedef enum { 97 AIOT_MQTT_VERSION_3_1, 98 AIOT_MQTT_VERSION_5_0 99 } aiot_mqtt_protocol_version; 100 101 /** 102 * @brief value-length 结构体. 103 * 104 * @details 105 * 106 * 用于MQTT 5.0协议中作为表示response topic/corelation data/disconnect reason等属性的通用的数据结构, 同时也是@ref user_property_t 的构成元素 107 */ 108 typedef struct { 109 uint16_t len; 110 uint8_t *value; 111 } len_value_t; 112 113 /** 114 * @brief MQTT 5.0协议中用户属性 115 * 116 * @details 117 * 118 * 作为@ref conn_property_t ,@ref pub_property_t ,@ref disconn_property_t 的结构体的成员 119 * 120 */ 121 typedef struct { 122 len_value_t key; 123 len_value_t value; 124 } user_property_t; 125 126 /* MQTT服务端支持的最大的用户属性的数目. */ 127 #define USER_PROPERTY_MAX (20) 128 129 /** 130 * @brief MQTT 5.0协议中, 下行的conack报文conack中的属性 131 */ 132 typedef struct { 133 uint8_t max_qos; 134 uint16_t topic_alias_max; 135 uint8_t *assigned_clientid; 136 uint32_t max_packet_size; 137 uint16_t server_receive_max; 138 uint8_t wildcard_subscription_available; 139 uint8_t subscription_identifier_available; 140 uint8_t shared_subscription_available; 141 user_property_t *user_property[USER_PROPERTY_MAX]; 142 } connack_property_t; 143 144 /** 145 * @brief MQTT 5.0协议中, 上行和下行pub报文中的属性. 146 */ 147 typedef struct { 148 uint32_t message_expire_interval; 149 uint16_t topic_alias; 150 len_value_t response_topic; 151 len_value_t correlation_data; 152 uint32_t subscription_identifier; 153 user_property_t *user_property[USER_PROPERTY_MAX]; 154 } pub_property_t; 155 156 /** 157 * @brief MQTT 5.0协议中, 上行的connect报文中的属性. 158 * 159 * @details 160 * 161 * 传入@ref aiot_mqtt_connect_with_prop 的MQTT报文类型 162 */ 163 typedef struct { 164 uint16_t topic_alias_max; /* topic 别名最大数量 */ 165 uint16_t client_receive_max; 166 user_property_t *user_property[USER_PROPERTY_MAX]; /* 用户属性 */ 167 } conn_property_t; 168 169 /** 170 * @brief MQTT 5.0协议中, 上行的disconnect报文中的属性. 171 * 172 * @details 173 * 174 * 传入@ref aiot_mqtt_disconnect_with_prop 的MQTT报文类型 175 * 176 */ 177 typedef struct { 178 len_value_t *reason_string; 179 user_property_t *user_property[USER_PROPERTY_MAX]; /* 用户属性 */ 180 } disconn_property_t; 181 182 /** 183 * @brief MQTT 5.0协议中, 上行的subscribe报文中的属性. 184 * 185 * @details 186 * 187 * 传入@ref aiot_mqtt_sub_with_prop 的MQTT报文类型 188 * 189 */ 190 typedef struct { 191 user_property_t *user_property[USER_PROPERTY_MAX]; 192 } sub_property_t; 193 194 /** 195 * @brief MQTT 5.0协议中, 上行的subscribe报文中的属性. 196 * 197 * @details 198 * 199 * 传入@ref aiot_mqtt_unsub_with_prop 的MQTT报文类型 200 * 201 */ 202 typedef struct { 203 user_property_t *user_property[USER_PROPERTY_MAX]; 204 } unsub_property_t; 205 206 207 typedef struct { 208 /** 209 * @brief MQTT报文类型, 更多信息请参考@ref aiot_mqtt_recv_type_t 210 */ 211 aiot_mqtt_recv_type_t type; 212 /** 213 * @brief MQTT报文联合体, 内容根据type进行选择 214 */ 215 union { 216 /** 217 * @brief MQTT PUBLISH报文 218 */ 219 struct { 220 uint8_t qos; 221 char *topic; 222 uint16_t topic_len; 223 uint8_t *payload; 224 uint32_t payload_len; 225 pub_property_t *pub_prop; /* pub报文中的属性. MQTT 5.0 特性*/ 226 } pub; 227 /** 228 * @brief AIOT_MQTTRECV_SUB_ACK 229 */ 230 struct { 231 int32_t res; 232 uint8_t max_qos; 233 uint16_t packet_id; 234 } sub_ack; 235 /** 236 * @brief AIOT_MQTTRECV_UNSUB_ACK 237 */ 238 struct { 239 uint16_t packet_id; 240 } unsub_ack; 241 /** 242 * @brief AIOT_MQTTRECV_PUB_ACK 243 */ 244 struct { 245 uint16_t packet_id; 246 } pub_ack; 247 248 /** 249 * @brief AIOT_MQTTRECV_CON_ACK 250 */ 251 struct { 252 uint8_t reason_code; 253 connack_property_t prop; /* 建连回复报文中的属性. MQTT 5.0 特性 */ 254 } con_ack; 255 256 /** 257 * @brief AIOT_MQTTRECV_DISCONNECT. MQTT 5.0特性. 258 */ 259 struct { 260 uint8_t reason_code; 261 } server_disconnect; 262 263 } data; 264 } aiot_mqtt_recv_t; 265 266 /** 267 * @brief MQTT报文接收回调函数原型 268 * 269 * @param[in] handle MQTT实例句柄 270 * @param[in] packet MQTT报文结构体, 存放收到的MQTT报文 271 * @param[in] userdata 用户上下文 272 * 273 * @return void 274 */ 275 typedef void (*aiot_mqtt_recv_handler_t)(void *handle, const aiot_mqtt_recv_t *packet, void *userdata); 276 277 /** 278 * @brief MQTT内部事件类型 279 */ 280 typedef enum { 281 /** 282 * @brief 当MQTT实例第一次连接网络成功时, 触发此事件 283 */ 284 AIOT_MQTTEVT_CONNECT, 285 /** 286 * @brief 当MQTT实例断开网络连接后重连成功时, 触发此事件 287 */ 288 AIOT_MQTTEVT_RECONNECT, 289 /** 290 * @brief 当MQTT实例断开网络连接时, 触发此事件 291 */ 292 AIOT_MQTTEVT_DISCONNECT 293 } aiot_mqtt_event_type_t; 294 295 typedef enum { 296 /** 297 * @brief MQTT实例网络连接由于网络故障而断开 298 */ 299 AIOT_MQTTDISCONNEVT_NETWORK_DISCONNECT, 300 /** 301 * @brief MQTT实例网络连接由于心跳丢失超过指定次数(@ref AIOT_MQTTOPT_HEARTBEAT_MAX_LOST )而断开 302 */ 303 AIOT_MQTTDISCONNEVT_HEARTBEAT_DISCONNECT 304 } aiot_mqtt_disconnect_event_type_t; 305 306 /** 307 * @brief MQTT内部事件 308 */ 309 typedef struct { 310 /** 311 * @brief MQTT内部事件类型. 更多信息请参考@ref aiot_mqtt_event_type_t 312 * 313 */ 314 aiot_mqtt_event_type_t type; 315 /** 316 * @brief MQTT事件数据联合体 317 */ 318 union { 319 /** 320 * @brief MQTT连接断开时, 具体的断开原因 321 */ 322 aiot_mqtt_disconnect_event_type_t disconnect; 323 } data; 324 } aiot_mqtt_event_t; 325 326 /** 327 * @brief MQTT事件回调函数 328 * 329 * @details 330 * 331 * 当MQTT内部事件被触发时, 调用此函数. 如连接成功/断开连接/重连成功 332 * 333 */ 334 typedef void (*aiot_mqtt_event_handler_t)(void *handle, const aiot_mqtt_event_t *event, void *userdata); 335 336 /** 337 * @brief 使用 @ref aiot_mqtt_setopt 配置 @ref AIOT_MQTTOPT_APPEND_TOPIC_MAP 时的数据 338 * 339 * @details 340 * 341 * 用于在建立MQTT连接前配置topic与相应的回调函数 342 * 343 */ 344 typedef struct { 345 char *topic; 346 aiot_mqtt_recv_handler_t handler; 347 void *userdata; 348 } aiot_mqtt_topic_map_t; 349 350 /** 351 * @brief @ref aiot_mqtt_setopt 函数的option参数. 对于下文每一个选项中的数据类型, 指的是@ref aiot_mqtt_setopt 中的data参数的数据类型 352 * 353 * @details 354 * 355 * 1. data的数据类型是char *时, 以配置@ref AIOT_MQTTOPT_HOST 为例: 356 * 357 * char *host = "xxx"; 358 * 359 * aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_HOST, host); 360 * 361 * 2. data的数据类型是其他数据类型时, 以配置@ref AIOT_MQTTOPT_PORT 为例: 362 * 363 * uint16_t port = 443; 364 * 365 * aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PORT, (void *)&port); 366 */ 367 typedef enum { 368 /** 369 * @brief MQTT 服务器的域名地址或者ip地址 370 * 371 * @details 372 * 373 * 阿里云物联网平台域名地址列表(必须使用自己的product key替换${pk}): 374 * 375 * 使用tcp或tls证书方式建联: 376 * 377 * | 域名地址 | 区域 | 端口号 378 * |-------------------------------------------------|---------|--------- 379 * | ${pk}.iot-as-mqtt.cn-shanghai.aliyuncs.com | 上海 | 443 380 * | ${pk}.iot-as-mqtt.ap-southeast-1.aliyuncs.com | 新加坡 | 443 381 * | ${pk}.iot-as-mqtt.ap-northeast-1.aliyuncs.com | 日本 | 443 382 * | ${pk}.iot-as-mqtt.us-west-1.aliyuncs.com | 美西 | 443 383 * | ${pk}.iot-as-mqtt.eu-central-1.aliyuncs.com | 德国 | 443 384 * 385 * 使用tls psk方式建联: 386 * 387 * | 域名地址 | 区域 | 端口号 388 * |-----------------------------------------|---------|--------- 389 * | ${pk}.itls.cn-shanghai.aliyuncs.com | 上海 | 1883 390 * 391 * 使用tls x509客户端证书方式建联: 392 * 393 * | 域名地址 | 区域 | 端口号 394 * |-------------------------------------|---------|--------- 395 * | x509.itls.cn-shanghai.aliyuncs.com | 上海 | 1883 396 * 397 * 数据类型: (char *) 398 */ 399 AIOT_MQTTOPT_HOST, 400 401 /** 402 * @brief MQTT 服务器的端口号 403 * 404 * @details 405 * 406 * 连接阿里云物联网平台时: 407 * 408 * 1. 如果使用的是tcp或者tls证书方式, 端口号设置为443 409 * 410 * 2. 如果使用的是tls psk和tls x509客户端证书方式, 端口号设置为1883 411 * 412 * 数据类型: (uint16_t *) 413 */ 414 AIOT_MQTTOPT_PORT, 415 416 /** 417 * @brief 设备的product key, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取 418 * 419 * @details 420 * 421 * 数据类型: (char *) 422 */ 423 AIOT_MQTTOPT_PRODUCT_KEY, 424 425 /** 426 * @brief 设备的device name, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取 427 * 428 * @details 429 * 430 * 数据类型: (char *) 431 */ 432 AIOT_MQTTOPT_DEVICE_NAME, 433 434 /** 435 * @brief 设备的device secret, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取 436 * 437 * @details 438 * 439 * 数据类型: (char *) 440 */ 441 AIOT_MQTTOPT_DEVICE_SECRET, 442 443 /** 444 * @brief 设备连接阿里云物联网平台时的扩展clientid 445 * 446 * @details 447 * 448 * 若需要上报模组商id和模组id以及os信息, 按以下格式填写: 449 * 450 * "mid=<模组ID>,pid=<模组商ID>,os=<操作系统>" 451 * 452 * 数据类型: (char *) 453 */ 454 AIOT_MQTTOPT_EXTEND_CLIENTID, 455 456 /** 457 * @brief 设备连接阿里云物联网平台时的安全模式, 使用标准的tcp或tls时无需配置 458 * 459 * @details 460 * 461 * 数据类型: (char *) 462 */ 463 AIOT_MQTTOPT_SECURITY_MODE, 464 465 /** 466 * @brief 使用自定义连接凭据连接mqtt服务器时, 凭据的username 467 * 468 * @details 469 * 470 * 数据类型: (char *) 471 */ 472 AIOT_MQTTOPT_USERNAME, 473 474 /** 475 * @brief 使用自定义连接凭据连接mqtt服务器时, 凭据的password 476 * 477 * @brief 478 * 479 * 数据类型: (char *) 480 */ 481 AIOT_MQTTOPT_PASSWORD, 482 483 /** 484 * @brief 使用自定义连接凭据连接mqtt服务器时, 凭据的clientid 485 * 486 * @details 487 * 488 * 数据类型: (char *) 489 */ 490 AIOT_MQTTOPT_CLIENTID, 491 492 /** 493 * @brief MQTT建联时, CONNECT报文中的心跳间隔参数 494 * 495 * @details 496 * 497 * 受阿里云物联网平台限制, 取值范围为30 ~ 1200s 498 * 499 * 1. 如果设置的值小于30, mqtt建联会被云端拒绝, @ref aiot_mqtt_connect 函数会返回@ref STATE_MQTT_CONNACK_RCODE_SERVER_UNAVAILABLE 错误 500 * 501 * 2. 如果设置的值大于1200, mqtt连接仍然可以建立, 但此参数会被服务器覆盖为1200 502 * 503 * 数据类型: (uint16_t *) 取值范围: 30 ~ 1200s 默认值: 1200s 504 */ 505 AIOT_MQTTOPT_KEEPALIVE_SEC, 506 507 /** 508 * @brief MQTT建联时, CONNECT报文中的clean session参数 509 * 510 * @details 511 * 512 * 1. 设备上线时如果clean session为0, 那么上线前服务器推送QoS1的消息会在此时推送给设备 513 * 514 * 2. 设备上线时如果clean session为1, 那么上线前服务器推送的QoS1的消息会被丢弃 515 * 516 * 数据类型: (uint8_t *) 取值范围: 0, 1 默认值: 1 517 */ 518 AIOT_MQTTOPT_CLEAN_SESSION, 519 520 /** 521 * @brief MQTT建联时, 网络使用的安全凭据 522 * 523 * @details 524 * 525 * 该配置项用于为底层网络配置@ref aiot_sysdep_network_cred_t 安全凭据数据 526 * 527 * 1. 若该选项不配置, 那么MQTT将以tcp方式直接建联 528 * 529 * 2. 若@ref aiot_sysdep_network_cred_t 中option配置为@ref AIOT_SYSDEP_NETWORK_CRED_NONE , MQTT将以tcp方式直接建联 530 * 531 * 3. 若@ref aiot_sysdep_network_cred_t 中option配置为@ref AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA , MQTT将以tls方式建联 532 * 533 * 4. 若@ref aiot_sysdep_network_cred_t 中option配置为@ref AIOT_SYSDEP_NETWORK_CRED_SVRCERT_PSK , MQTT将以tls psk方式建联 534 * 535 * 数据类型: (aiot_sysdep_network_cred_t *) 536 */ 537 AIOT_MQTTOPT_NETWORK_CRED, 538 539 /** 540 * @brief MQTT建联时, 建立网络连接的超时时间 541 * 542 * @details 543 * 544 * 指建立socket连接的超时时间 545 * 546 * 数据类型: (uint32_t *) 默认值: (5 *1000) ms 547 * 548 */ 549 AIOT_MQTTOPT_CONNECT_TIMEOUT_MS, 550 551 /** 552 * @brief 配置MQTT PINGREQ报文发送时间间隔. (心跳发送间隔) 553 * 554 * @details 555 * 556 * 数据类型: (uint32_t *) 默认值: (25 * 1000) ms 557 */ 558 AIOT_MQTTOPT_HEARTBEAT_INTERVAL_MS, 559 560 /** 561 * @brief 配置MQTT PINGRESP报文允许连续丢失的最大次数, 当超过这个次数时, 触发重连机制 562 * 563 * @details 564 * 565 * 数据类型: (uint8_t *) 默认值: (2) 566 */ 567 AIOT_MQTTOPT_HEARTBEAT_MAX_LOST, 568 569 /** 570 * @brief 打开/关闭MQTT重连机制 571 * 572 * @details 573 * 574 * 数据类型: (uint8_t *) 取值范围: 0, 1 默认值: 1 575 */ 576 AIOT_MQTTOPT_RECONN_ENABLED, 577 578 /** 579 * @brief 当由于心跳丢失或者网络断开触发重连机制时, 尝试重连的时间间隔 580 * 581 * @details 582 * 583 * 数据类型: (uint32_t *) 默认值: (2 * 1000) ms 584 */ 585 AIOT_MQTTOPT_RECONN_INTERVAL_MS, 586 587 /** 588 * @brief MQTT发送数据时, 在协议栈花费的最长时间 589 * 590 * @details 591 * 592 * 数据类型: (uint32_t *) 默认值: (5 * 1000) ms 593 */ 594 AIOT_MQTTOPT_SEND_TIMEOUT_MS, 595 596 /** 597 * @brief MQTT接收数据时, 在协议栈花费的最长时间 598 * 599 * @details 600 * 601 * 数据类型: (uint32_t *) 默认值: (5 * 1000) ms 602 */ 603 AIOT_MQTTOPT_RECV_TIMEOUT_MS, 604 605 /** 606 * @brief QoS1消息重发间隔 607 * 608 * @details 609 * 610 * 当发送qos1 MQTT PUBLISH报文后, 如果在@ref AIOT_MQTTOPT_REPUB_TIMEOUT_MS 时间内未收到mqtt PUBACK报文, 611 * @ref aiot_mqtt_process 会重新发送此qo1 MQTT PUBLISH报文, 直到收到PUBACK报文为止 612 * 613 * 数据类型: (uint32_t *) 默认值: (3 * 1000) ms 614 */ 615 AIOT_MQTTOPT_REPUB_TIMEOUT_MS, 616 617 /** 618 * @brief 销毁MQTT实例时, 等待其他api执行完毕的时间 619 * 620 * @details 621 * 622 * 当调用@ref aiot_mqtt_deinit 销毁MQTT实例时, 若继续调用其他aiot_mqtt_xxx API, API会返回@ref STATE_USER_INPUT_EXEC_DISABLED 错误 623 * 624 * 此时, 用户应该停止调用其他aiot_mqtt_xxx API 625 * 626 * 数据类型: (uint32_t *) 默认值: (2 * 1000) ms 627 */ 628 AIOT_MQTTOPT_DEINIT_TIMEOUT_MS, 629 630 /** 631 * @brief 从MQTT服务器收取的数据从此默认回调函数进行通知 632 * 633 * @details 634 * 635 * 1. 若没有配置该回调函数, 当有消息到达但找不到对应的已注册topic时, 消息会被丢弃 636 * 637 * 2. 若已配置该回调函数, 当有消息到达但找不到对应的已注册topic时, 消息从此默认回调函数进行通知 638 * 639 * 数据类型: ( @ref aiot_mqtt_recv_handler_t ) 640 */ 641 AIOT_MQTTOPT_RECV_HANDLER, 642 643 /** 644 * @brief MQTT客户端内部发生的事件会从此回调函数进行通知, 如上线/断线/重新上线 645 * 646 * @details 647 * 648 * 数据类型: ( @ref aiot_mqtt_event_handler_t ) 649 */ 650 AIOT_MQTTOPT_EVENT_HANDLER, 651 652 /** 653 * @brief 可在MQTT建立连接之前配置MQTT topic与其对应的回调函数 654 * 655 * @details 656 * 657 * 数据类型: ( @ref aiot_mqtt_topic_map_t ) 658 */ 659 AIOT_MQTTOPT_APPEND_TOPIC_MAP, 660 661 /** 662 * @brief 取消之前建立的MQTT topic与其回调函数的对应关系 663 * 664 * @details 665 * 666 * 数据类型: ( @ref aiot_mqtt_topic_map_t ) 667 */ 668 AIOT_MQTTOPT_REMOVE_TOPIC_MAP, 669 670 /** 671 * @brief 在publish消息的topic上附加请求ID字符串, 用于全链路日志追踪 672 * 673 * @details 674 * 675 * 数据类型: (uint8_t *) 默认值: 0 676 * 677 * 配置为0则不附加请求ID字符串, 配置为1将附加请求ID字符串 678 */ 679 AIOT_MQTTOPT_APPEND_REQUESTID, 680 681 /** 682 * @brief 用户需要SDK暂存的上下文 683 * 684 * @details 685 * 686 * 1. 该上下文会在@ref AIOT_MQTTOPT_RECV_HANDLER 和@ref AIOT_MQTTOPT_EVENT_HANDLER 中传回给用户 687 * 688 * 2. 当使用@ref AIOT_MQTTOPT_APPEND_TOPIC_MAP 或者@ref aiot_mqtt_sub 时未指定userdata, 该上下文也会传给这些回调函数 689 * 690 * 数据类型: (void *) 691 */ 692 AIOT_MQTTOPT_USERDATA, 693 694 /** 695 * @brief 设置MQTT 协议的版本号 696 * 697 * @details 698 * 699 * 1. 默认协议版本号是3.1.1 700 * 701 * 2. 用户可以使用该选项将版本号设置为AIOT_MQTT_VERSION_5_0 702 * 703 * 数据类型: (void *) 704 */ 705 AIOT_MQTTOPT_VERSION, 706 707 /** 708 * @brief MQTT 5.0特性. 设置是否要使能assigned clentid功能 709 * 710 * @details 711 * 712 * 1. 默认不使能 713 * 714 * 2. 用户可以设置值1将该功能使能 715 * 716 * 数据类型: (void *) 717 */ 718 AIOT_MQTTOPT_ASSIGNED_CLIENTID, 719 720 /** 721 * @brief MQTT 5.0特性. 设置是否要使能设备端流控功能 722 * 723 * @details 724 * 725 * 1. 默认不使能 726 * 727 * 2. 用户可以设置值1将该功能使能 728 * 729 * 数据类型: (void *) 730 */ 731 AIOT_MQTTOPT_FLOW_CONTROL_ENABLED, 732 733 AIOT_MQTTOPT_MAX 734 } aiot_mqtt_option_t; 735 736 /** 737 * @brief 初始化mqtt实例并设置默认参数 738 * 739 * @return void* 740 * @retval 非NULL MQTT实例句柄 741 * @retval NULL 初始化失败, 一般是内存分配失败导致 742 * 743 */ 744 void *aiot_mqtt_init(void); 745 746 /** 747 * @brief 设置mqtt参数 748 * 749 * @details 750 * 751 * 下面列出常用的配置选项, 至少需要配置以下选项才可使用MQTT的基本功能 752 * 753 * 其余配置选项均设有默认值, 可按业务需要进行调整 754 * 755 * + `AIOT_MQTTOPT_HOST`: 配置连接的阿里云MQTT站点地址 756 * 757 * + `AIOT_MQTTOPT_PORT`: 配置连接的阿里云MQTT站点端口号 758 * 759 * + `AIOT_MQTTOPT_PRODUCT_KEY`: 配置设备的 productKey 760 * 761 * + `AIOT_MQTTOPT_DEVICE_NAME`: 配置设备的 deviceName 762 * 763 * + `AIOT_MQTTOPT_DEVICE_SECRET`: 配置设备的 deviceSecret 764 * 765 * + `AIOT_MQTTOPT_NETWORK_CRED`: 配置建立MQTT连接时的安全凭据 766 * 767 * + `AIOT_MQTTOPT_RECV_HANDLER`: 配置默认的数据接收回调函数 768 * 769 * + `AIOT_MQTTOPT_EVENT_HANDLER`: 配置MQTT事件通知回调函数 770 * 771 * @param[in] handle mqtt句柄 772 * @param[in] option 配置选项, 更多信息请参考@ref aiot_mqtt_option_t 773 * @param[in] data 配置选项数据, 更多信息请参考@ref aiot_mqtt_option_t 774 * 775 * @return int32_t 776 * @retval <STATE_SUCCESS 参数设置失败, 更多信息请参考@ref aiot_state_api.h 777 * @retval >=STATE_SUCCESS 参数设置成功 778 * 779 */ 780 int32_t aiot_mqtt_setopt(void *handle, aiot_mqtt_option_t option, void *data); 781 782 /** 783 * @brief 释放mqtt实例句柄的资源 784 * 785 * @param[in] handle 指向mqtt实例句柄的指针 786 * 787 * @return int32_t 788 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 789 * @retval >=STATE_SUCCESS 执行成功 790 * 791 */ 792 int32_t aiot_mqtt_deinit(void **handle); 793 794 /** 795 * @brief 与MQTT服务器建立连接 796 * 797 * @details 798 * 799 * 使用@ref aiot_mqtt_setopt 配置的mqtt连接参数连接mqtt服务器, 使用的建联参数按如下顺序选择 800 * 801 * 1. 若配置了以下选项, 直接用配置的连接参数连接 @ref AIOT_MQTTOPT_HOST 选项指定的任意MQTT服务器 802 * 803 * + @ref AIOT_MQTTOPT_USERNAME 804 * + @ref AIOT_MQTTOPT_PASSWORD 805 * + @ref AIOT_MQTTOPT_CLIENTID 806 * 807 * 2. 若配置了以下选项, 则强制以阿里云平台的签名算法计算连接参数作为MQTT的用户名/密码, 连接阿里云平台 808 * 809 * + @ref AIOT_MQTTOPT_PRODUCT_KEY 810 * + @ref AIOT_MQTTOPT_DEVICE_NAME 811 * + @ref AIOT_MQTTOPT_DEVICE_SECRET 812 * 813 * @param[in] handle MQTT实例句柄 814 * 815 * @return int32_t 816 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 817 * @retval >=STATE_SUCCESS 执行成功 818 * 819 * @note 820 * 821 * 当配置@ref AIOT_MQTTOPT_USERNAME , @ref AIOT_MQTTOPT_PASSWORD 和@ref AIOT_MQTTOPT_CLIENTID 配置自定义连接凭据时, 822 * 823 * 此函数会忽略@ref AIOT_MQTTOPT_PRODUCT_KEY , @ref AIOT_MQTTOPT_DEVICE_NAME 和@ref AIOT_MQTTOPT_DEVICE_SECRET, 824 * 825 * 直接使用自定义凭据连接指定的MQTT服务器 826 */ 827 int32_t aiot_mqtt_connect(void *handle); 828 829 /** 830 * @brief 与MQTT服务器断开连接 831 * 832 * @details 833 * 834 * 向MQTT服务器发送MQTT DISCONNECT报文, 然后断开网络连接 835 * 836 * 如果需要再次与MQTT服务器建立连接, 调用@ref aiot_mqtt_connect 即可 837 * 838 * @param[in] handle MQTT实例句柄 839 * 840 * @return int32_t 841 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 842 * @retval >=STATE_SUCCESS 执行成功 843 */ 844 int32_t aiot_mqtt_disconnect(void *handle); 845 846 /** 847 * @brief 发送MQTT PINGREQ报文, 用于维持心跳 848 * 849 * @details 850 * 851 * @ref aiot_mqtt_process 包含了定时发送心跳的机制, 如果有特殊需要的话, 可以使用此函数直接发送心跳报文 852 * 853 * @param[in] handle MQTT实例句柄 854 * 855 * @return int32_t 856 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 857 * @retval >=STATE_SUCCESS 执行成功 858 */ 859 int32_t aiot_mqtt_heartbeat(void *handle); 860 861 /** 862 * @brief 此函数用于处理定时心跳发送和qos1消息的重传逻辑 863 * 864 * @details 865 * 866 * 1. 发送心跳至mqtt broker以维护mqtt连接, 心跳发送间隔由@ref AIOT_MQTTOPT_HEARTBEAT_INTERVAL_MS 配置项控制 867 * 868 * 2. 如果一条qos1的mqtt PUBLISH报文在@ref AIOT_MQTTOPT_REPUB_TIMEOUT_MS 时间内没有收到mqtt PUBACK应答报文, 该函数会重发此消息, 直到成功为止 869 * 870 * @param[in] handle MQTT实例句柄 871 * 872 * @return int32_t 873 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 874 * @retval >=STATE_SUCCESS 执行成功 875 * 876 * @note 877 * 878 * 该函数为非阻塞, 需要间歇性被调用, 调用间隔应当小于@ref AIOT_MQTTOPT_HEARTBEAT_INTERVAL_MS 和@ref AIOT_MQTTOPT_REPUB_TIMEOUT_MS 时间内没有收到mqtt的最小值, 879 * 880 * 以确保心跳发送和QoS1消息的重传逻辑正常工作 881 */ 882 int32_t aiot_mqtt_process(void *handle); 883 884 /** 885 * @brief 发送一条PUBLISH报文到MQTT服务器, QoS为0, 用于发布指定的消息 886 * 887 * @param[in] handle MQTT实例句柄 888 * @param[in] topic 指定MQTT PUBLISH报文的topic 889 * @param[in] payload 指定MQTT PUBLISH报文的payload 890 * @param[in] payload_len 指定MQTT PUBLISH报文的payload_len 891 * @param[in] qos 指定mqtt的qos值, 仅支持qos0和qos1 892 * 893 * @return int32_t 894 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 895 * @retval >=STATE_SUCCESS 执行成功 896 */ 897 int32_t aiot_mqtt_pub(void *handle, char *topic, uint8_t *payload, uint32_t payload_len, uint8_t qos); 898 899 /** 900 * @brief 发送一条mqtt SUBSCRIBE报文到MQTT服务器, 用于订阅指定的topic 901 * 902 * @param[in] handle MQTT实例句柄 903 * @param[in] topic 指定MQTT SUBSCRIBE报文的topic 904 * @param[in] handler 与topic对应的MQTT PUBLISH报文回调函数, 当有消息发布到topic时, 该回调函数被调用 905 若handler为NULL传入, 则SDK调用@ref AIOT_MQTTOPT_RECV_HANDLER 配置的回调函数 906 若多次调用aiot_mqtt_sub()并对同一topic指定不同的handler, 有消息到达时不同handler都会被调用到 907 * @param[in] qos 指定topic期望mqtt服务器支持的最大qos值, 仅支持qos0和qos1 908 * @param[in] userdata 可让SDK代为保存的用户上下文, 当回调函数被调用时, 此上下文会通过handler传回给用户 909 * 若未指定该上下文, 那么通过@ref AIOT_MQTTOPT_USERDATA 配置的上下文会通过handler传回给用户 910 * 911 * @return int32_t 912 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 913 * @retval >=STATE_SUCCESS 执行成功 914 */ 915 int32_t aiot_mqtt_sub(void *handle, char *topic, aiot_mqtt_recv_handler_t handler, uint8_t qos, void *userdata); 916 917 /** 918 * @brief 发送一条mqtt UNSUBSCRIBE报文到MQTT服务器, 用于取消订阅指定的topic 919 * 920 * @param[in] handle MQTT实例句柄 921 * @param[in] topic 指定MQTT UNSUBSCRIBE报文的topic 922 * 923 * @return int32_t 924 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 925 * @retval >=STATE_SUCCESS 执行成功 926 */ 927 int32_t aiot_mqtt_unsub(void *handle, char *topic); 928 929 /** 930 * @brief 尝试从网络上接收MQTT报文 931 * 932 * @details 933 * 934 * 除了从网络上接收MQTT报文之外, 本函数也包含了重连机制 935 * 936 * 1. 当MQTT心跳丢失超过@ref AIOT_MQTTOPT_HEARTBEAT_MAX_LOST 配置的次数时, 触发重连机制 937 * 938 * + 重连间隔由 @ref AIOT_MQTTOPT_RECONN_INTERVAL_MS 指定 939 * 940 * 2. 当SDK检测到网络断开时, 触发重连机制 941 * 942 * + 重连间隔由 @ref AIOT_MQTTOPT_RECONN_INTERVAL_MS 指定 943 * 944 * @param[in] handle 945 * 946 * @retval STATE_SYS_DEPEND_NWK_READ_LESSDATA 执行成功, 此时网络上暂无可以收取的MQTT报文 947 * @retval >=STATE_SUCCESS 执行成功 948 * @retval 其他返回值 执行失败, 更多信息请参考@ref aiot_state_api.h 949 * 950 * @note 951 * 952 * 当网络连接正常并且@ref aiot_mqtt_deinit 未被调用时, 该函数为阻塞, 需要持续被调用 953 * 954 * 1. 当网络连接断开时, 该函数会立即返回, 此时返回值为@ref STATE_SYS_DEPEND_NWK_CLOSED 955 * 956 * 2. 当@ref aiot_mqtt_deinit 被调用时, 该函数会立即返回, 此时返回值为@ref STATE_USER_INPUT_EXEC_DISABLED 957 */ 958 int32_t aiot_mqtt_recv(void *handle); 959 960 /** 961 * @brief 与MQTT服务器建立连接. 以MQTT 5.0协议的方式接入, 支持5.0的特性. 962 * 在调用这个接口前, 需要确保已经通过AIOT_MQTTOPT_VERSION的方式, 设置过版本号为AIOT_MQTT_VERSION_5_0 963 * @details 964 * 965 * 使用@ref aiot_mqtt_setopt 配置的mqtt连接参数连接mqtt服务器, 使用的建联参数按如下顺序选择 966 * 967 * 1. 若配置了以下选项, 直接用配置的连接参数连接 @ref AIOT_MQTTOPT_HOST 选项指定的任意MQTT服务器 968 * 969 * + @ref AIOT_MQTTOPT_USERNAME 970 * + @ref AIOT_MQTTOPT_PASSWORD 971 * + @ref AIOT_MQTTOPT_CLIENTID 972 * 973 * 2. 若配置了以下选项, 则强制以阿里云平台的签名算法计算连接参数作为MQTT的用户名/密码, 连接阿里云平台 974 * 975 * + @ref AIOT_MQTTOPT_PRODUCT_KEY 976 * + @ref AIOT_MQTTOPT_DEVICE_NAME 977 * + @ref AIOT_MQTTOPT_DEVICE_SECRET 978 * 979 * @param[in] handle MQTT实例句柄 980 * @param[in] conn_prop 指定MQTT CONNECT报文的属性 981 * 982 * @return int32_t 983 * @retval STATE_MQTT_INVALID_PROTOCOL_VERSION mqtt协议的版本号不对, 没有通过AIOT_MQTTOPT_VERSION将版本号将设置为5.0 984 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 985 * @retval >=STATE_SUCCESS 执行成功 986 * 987 * @note 988 * 989 * 当配置@ref AIOT_MQTTOPT_USERNAME , @ref AIOT_MQTTOPT_PASSWORD 和@ref AIOT_MQTTOPT_CLIENTID 配置自定义连接凭据时, 990 * 991 * 此函数会忽略@ref AIOT_MQTTOPT_PRODUCT_KEY , @ref AIOT_MQTTOPT_DEVICE_NAME 和@ref AIOT_MQTTOPT_DEVICE_SECRET, 992 * 993 * 直接使用自定义凭据连接指定的MQTT服务器 994 */ 995 int32_t aiot_mqtt_connect_with_prop(void *handle, conn_property_t *conn_prop); 996 997 /** 998 * @brief 发送一条PUBLISH报文到MQTT服务器, QoS为0, 用于发布指定的消息 999 * 以MQTT 5.0协议的方式接入, 支持5.0的特性. 1000 * 在调用这个接口前, 需要确保已经通过AIOT_MQTTOPT_VERSION的方式, 设置过版本号为AIOT_MQTT_VERSION_5_0 1001 * 1002 * @param[in] handle MQTT实例句柄 1003 * @param[in] topic 指定MQTT PUBLISH报文的topic 1004 * @param[in] payload 指定MQTT PUBLISH报文的payload 1005 * @param[in] payload_len 指定MQTT PUBLISH报文的payload_len 1006 * @param[in] qos 指定mqtt的qos值, 仅支持qos0和qos1 1007 * @param[in] pub_prop 指定MQTT PUB报文的属性 1008 * 1009 * @return int32_t 1010 * @retval STATE_MQTT_INVALID_PROTOCOL_VERSION mqtt协议的版本号不对, 没有通过AIOT_MQTTOPT_VERSION将版本号将设置为5.0 1011 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 1012 * @retval >=STATE_SUCCESS 执行成功 1013 */ 1014 int32_t aiot_mqtt_pub_with_prop(void *handle, char *topic, uint8_t *payload, uint32_t payload_len, uint8_t qos, 1015 pub_property_t *pub_prop); 1016 1017 /** 1018 * @brief 与MQTT服务器断开连接 1019 * 以MQTT 5.0协议的方式接入, 支持5.0的特性. 1020 * 在调用这个接口前, 需要确保已经通过AIOT_MQTTOPT_VERSION的方式, 设置过版本号为AIOT_MQTT_VERSION_5_0 1021 1022 * @details 1023 * 1024 * 向MQTT服务器发送MQTT DISCONNECT报文, 然后断开网络连接 1025 * 1026 * 如果需要再次与MQTT服务器建立连接, 调用@ref aiot_mqtt_connect 即可 1027 * 1028 * @param[in] handle MQTT实例句柄 1029 * @param[in] reason_code 指定MQTT DISCONNECT的原因 1030 * @param[in] disconn_property 指定MQTT DISCONNECT报文的属性 1031 * 1032 * @return int32_t 1033 * @retval STATE_MQTT_INVALID_PROTOCOL_VERSION mqtt协议的版本号不对, 没有通过AIOT_MQTTOPT_VERSION将版本号将设置为5.0 1034 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 1035 * @retval >=STATE_SUCCESS 执行成功 1036 */ 1037 int32_t aiot_mqtt_disconnect_with_prop(void *handle, uint8_t reason_code, disconn_property_t *disconn_property); 1038 1039 /** 1040 * @brief 发送一条mqtt SUBSCRIBE报文到MQTT服务器, 用于订阅指定的topic 1041 * 以MQTT 5.0协议的方式接入, 支持5.0的特性. 1042 * 在调用这个接口前, 需要确保已经通过AIOT_MQTTOPT_VERSION的方式, 设置过版本号为AIOT_MQTT_VERSION_5_0 1043 1044 * 1045 * @param[in] handle MQTT实例句柄 1046 * @param[in] topic 指定MQTT SUBSCRIBE报文的topic 1047 * @param[in] handler 与topic对应的MQTT PUBLISH报文回调函数, 当有消息发布到topic时, 该回调函数被调用 1048 若handler为NULL传入, 则SDK调用@ref AIOT_MQTTOPT_RECV_HANDLER 配置的回调函数 1049 若多次调用aiot_mqtt_sub()并对同一topic指定不同的handler, 有消息到达时不同handler都会被调用到 1050 * @param[in] qos 指定topic期望mqtt服务器支持的最大qos值, 仅支持qos0和qos1 1051 * @param[in] userdata 可让SDK代为保存的用户上下文, 当回调函数被调用时, 此上下文会通过handler传回给用户 1052 * 若未指定该上下文, 那么通过@ref AIOT_MQTTOPT_USERDATA 配置的上下文会通过handler传回给用户 1053 * @param[in] sub_prop 指定MQTT SUBSCRIBE报文的属性 1054 * 1055 * @return int32_t 1056 * @retval STATE_MQTT_INVALID_PROTOCOL_VERSION mqtt协议的版本号不对, 没有通过AIOT_MQTTOPT_VERSION将版本号将设置为5.0 1057 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 1058 * @retval >=STATE_SUCCESS 执行成功 1059 */ 1060 int32_t aiot_mqtt_sub_with_prop(void *handle, char *topic, aiot_mqtt_recv_handler_t handler, uint8_t qos, 1061 void *userdata, sub_property_t *sub_prop); 1062 1063 /** 1064 * @brief 发送一条mqtt UNSUBSCRIBE报文到MQTT服务器, 用于取消订阅指定的topic 1065 * 以MQTT 5.0协议的方式接入, 支持5.0的特性. 1066 * 在调用这个接口前, 需要确保已经通过AIOT_MQTTOPT_VERSION的方式, 设置过版本号为AIOT_MQTT_VERSION_5_0 1067 * 1068 * @param[in] handle MQTT实例句柄 1069 * @param[in] topic 指定MQTT UNSUBSCRIBE报文的topic 1070 * @param[in] unsub_prop 指定MQTT UNSUBSCRIBE报文的属性 1071 * 1072 * @return int32_t 1073 * @retval STATE_MQTT_INVALID_PROTOCOL_VERSION mqtt协议的版本号不对, 没有通过AIOT_MQTTOPT_VERSION将版本号将设置为5.0 1074 * @retval <STATE_SUCCESS 执行失败, 更多信息请参考@ref aiot_state_api.h 1075 * @retval >=STATE_SUCCESS 执行成功 1076 */ 1077 int32_t aiot_mqtt_unsub_with_prop(void *handle, char *topic, unsub_property_t *unsub_prop); 1078 1079 #if defined(__cplusplus) 1080 } 1081 #endif 1082 1083 #endif 1084 1085