本文以C Link SDK中的Demo文件./demos/dynregmq_basic_demo.c
为例,介绍如何调用Link SDK的API,向物联网平台发起MQTT协议的请求,动态注册设备,获取激活设备所需的认证信息。
背景信息
定制SDK时,在SDK定制页面的设备认证方案区域,需选中动态注册。使用本示例前,请确保您已阅读并了解MQTT动态注册的MQTT动态注册使用说明。
步骤一:初始化
添加头文件。
#include "aiot_state_api.h" #include "aiot_sysdep_api.h" #include "aiot_dynregmq_api.h"
配置底层依赖和日志输出。
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);
调用aiot_dynregmq_init,创建
dynregmq
客户端实例,并初始化默认参数。dynregmq_handle = aiot_dynregmq_init(); if (dynregmq_handle == NULL) { printf("aiot_dynregmq_init failed\n"); return -1; }
步骤二:配置功能
调用aiot_dynregmq_setopt,配置以下功能。
更多功能的配置项,请参见MQTT动态注册配置项。
配置连接参数。
示例代码:
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使用。
配置消息回调。
配置消息回调函数。
示例代码:
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
被调用时,该值会被传回。
定义消息回调函数。
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,而是ClientId、UserName、Password。
您可以在
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);