本文以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);