MQTT动态注册使用示例

本文以C Link SDK中的Demo文件./demos/dynregmq_basic_demo.c为例,介绍如何调用Link SDK的API,向物联网平台发起MQTT协议的请求,动态注册设备,获取激活设备所需的认证信息

背景信息

定制SDK时,在SDK定制页面的设备认证方案区域,需选中动态注册。使用本示例前,请确保您已阅读并了解MQTT动态注册的MQTT动态注册使用说明

步骤一:初始化

  1. 添加头文件。

    #include "aiot_state_api.h"
    #include "aiot_sysdep_api.h"
    #include "aiot_dynregmq_api.h"
  2. 配置底层依赖和日志输出。

        aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
        aiot_state_set_logcb(demo_state_logcb);
  3. 调用aiot_dynregmq_init,创建dynregmq客户端实例,并初始化默认参数。

        dynregmq_handle = aiot_dynregmq_init();
        if (dynregmq_handle == NULL) {
            printf("aiot_dynregmq_init failed\n");
            return -1;
        }

步骤二:配置功能

调用aiot_dynregmq_setopt,配置以下功能。

  1. 配置连接参数

  2. 配置消息回调

  3. 更多功能的配置项,请参见MQTT动态注册配置项

  4. 配置连接参数

    • 示例代码:

          char *product_key       = "a18wP******";
          char *product_secret    = "CpIlPVCXI7******";
          char *device_name       = "LightSwitch";
          char         *mqtt_host = "iot-06******.mqtt.iothub.aliyuncs.com"; 
          uint8_t skip_pre_regist =1;
          ……
          /* 配置连接的服务器地址。 */
          aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_HOST, (void *)host);
          /* 配置连接的服务器端口。 */
          aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_PORT, (void *)&port);
          /* 配置设备ProductKey。 */
          aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_PRODUCT_KEY, (void *)product_key);
          /* 配置设备ProductSecret。 */
          aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_PRODUCT_SECRET, (void *)product_secret);
          /* 配置设备DeviceName */
          aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_DEVICE_NAME, (void *)device_name);
          /* 配置网络连接的安全凭据。 */
          aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_NETWORK_CRED, (void *)&cred);
          /* 配置是否使用免预注册认证方式。 */
          aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_NO_WHITELIST, (void *)&skip_pre_regist);
          ...
          ...
    • 相关参数:

      参数

      示例

      说明

      mqtt_host

      iot-06******.mqtt.iothub.aliyuncs.com

      设备的接入域名。

      接入域名格式为${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com

      skip_pre_regist

      1

      认证方式是否为免预注册。

      • 0:预注册

      • 1:免预注册

      重要

      关于一型一密预注册和免预注册的更多信息,请参见一型一密

      product_key

      a18wP******

      在物联网平台创建产品时,保存的产品的ProductKey和ProductSecret。更多信息,请参见创建产品

      product_secret

      CpIlPVCXI7******

      device_name

      LightSwitch

      设备的名称。

      因设备激活时会校验DeviceName,建议您采用可以直接从设备中读取到的ID,如设备的MAC地址、IMEI或SN码等,作为DeviceName使用。

  5. 配置消息回调

    1. 配置消息回调函数。

      • 示例代码:

         int main(int argc, char *argv[])
        {
            ……
            ……
            aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_RECV_HANDLER, (void *)demo_dynregmq_recv_handler);
            aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_USERDATA, (void *)&demo_info);
            ……
            ……
        }
      • 相关参数:

        配置项

        示例值

        说明

        AIOT_DYNREGMQOPT_RECV_HANDLER

        demo_dynregmq_recv_handler

        设置消息回调。当接收消息时,根据该回调函数的设置,执行对应的处理。

        AIOT_DYNREGMQOPT_USERDATA

        &demo_info

        设置上下文。当demo_dynregmq_recv_handler被调用时,该值会被传回。

    2. 定义消息回调函数。

      void demo_dynregmq_recv_handler(void *handle, const aiot_dynregmq_recv_t *packet, void *userdata)
      {
          switch (packet->type) {
              /* TODO: 回调中需保存packet指向的空间内容,回调返回后, 这些空间会被释放。 */
              case AIOT_DYNREGMQRECV_DEVICEINFO_WL: {
                  if (strlen(packet->data.deviceinfo_wl.device_secret) >= sizeof(demo_devinfo_wl.device_secret)) {
                      break;
                  }
                  /* 预注册方式认证时, 确保持久保存device_secret。 */
                  memset(&demo_devinfo_wl, 0, sizeof(demo_devinfo_wl_t));
                  memcpy(demo_devinfo_wl.device_secret, packet->data.deviceinfo_wl.device_secret,
                         strlen(packet->data.deviceinfo_wl.device_secret));
              }
              break;
              /* TODO: 回调中需保存packet指向的空间内容,回调返回后, 这些空间会被释放。 */
              case AIOT_DYNREGMQRECV_DEVICEINFO_NWL: {
                  if (strlen(packet->data.deviceinfo_nwl.clientid) >= sizeof(demo_devinfo_nwl.conn_clientid) ||
                      strlen(packet->data.deviceinfo_nwl.username) >= sizeof(demo_devinfo_nwl.conn_username) ||
                      strlen(packet->data.deviceinfo_nwl.password) >= sizeof(demo_devinfo_nwl.conn_password)) {
                      break;
                  }
                  /* 免预注册方式认证时, 确保持久化保存clientid, username和password。 */
                  memset(&demo_devinfo_nwl, 0, sizeof(demo_devinfo_nwl_t));
                  memcpy(demo_devinfo_nwl.conn_clientid, packet->data.deviceinfo_nwl.clientid,
                         strlen(packet->data.deviceinfo_nwl.clientid));
                  memcpy(demo_devinfo_nwl.conn_username, packet->data.deviceinfo_nwl.username,
                         strlen(packet->data.deviceinfo_nwl.username));
                  memcpy(demo_devinfo_nwl.conn_password, packet->data.deviceinfo_nwl.password,
                         strlen(packet->data.deviceinfo_nwl.password));
              }
              break;
              default: {
              }
              break;
          }
      }

步骤三:发送请求

调用aiot_dynregmq_send_request,根据配置连接的参数,向服务器发起动态注册请求。

     res = aiot_dynregmq_send_request(dynregmq_handle);
    if (res < STATE_SUCCESS) {
        printf("aiot_dynregmq_send_request failed: -0x%04X\n", -res);
        return -1;
    }        

步骤四:接收应答

注册请求消息发送后,物联网平台返回应答报文。设备端调用aiot_dynregmq_recv,接收应答消息,根据消息回调函数,执行对应处理。

    res = aiot_dynregmq_recv(dynregmq_handle);
    if (res < STATE_SUCCESS) {
        printf("aiot_dynregmq_recv failed: -0x%04X\n", -res);
        return -1;
    }         

例程仅做打印操作,但在实际业务环境中,您还需编写代码,将返回的设备身份认证信息,保存至本地。每当设备登录时,通过该认证信息建立与物联网平台的连接。

    if (skip_pre_regist == 0) {
        printf("device secret: %s\n", demo_devinfo_wl.device_secret);
    } else {
        printf("clientid: %s\n", demo_devinfo_nwl.conn_clientid);
        printf("username: %s\n", demo_devinfo_nwl.conn_username);
        printf("password: %s\n", demo_devinfo_nwl.conn_password);
    }

步骤五:退出程序

调用aiot_dynregmq_deinit,销毁dynregmq客户端实例,释放资源。

    res = aiot_dynregmq_deinit(&dynregmq_handle);            

后续步骤

  • 例程文件配置完成后,需进行编译,生成可执行文件./output/dynregmq-basic-demo

    更多信息,请参见编译与运行

  • 关于运行结果的详细说明,请参见MQTT动态注册运行日志

  • 一型一密免预注册下发的密钥不是DeviceSecret,而是ClientIdUserNamePassword

    您可以在mqtt_basic_demo.c中通过AIOT_MQTTOPT_USERNAME, AIOT_MQTTOPT_PASSWORD, AIOT_MQTTOPT_CLIENTID这几个配置项设置上述密钥,调用aiot_mqtt_connect连云,参考代码如下。

     char *user_name  = "demo_user_name";
     char *password = "demo_passwd";
     char *client_id = "demo_client_id";
     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_USERNAME, user_name);
     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PASSWORD, password);
     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_CLIENTID, client_id);
     res = aiot_mqtt_connect(mqtt_handle);