本文以C Link SDK中的Demo文件./demos/subdev_basic_demo.c為例,介紹如何調用Link SDK的API,幫助您實現子設備通過網關接入物聯網平臺。
背景信息
步驟一:初始化
添加頭文件。
…… …… #include "aiot_subdev_api.h"
配置底層依賴和日志輸出。
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);
調用aiot_subdev_init,創建
subde
客戶端實例,并初始化默認參數。subdev_handle = aiot_subdev_init(); if (subdev_handle == NULL) { printf("aiot_subdev_init failed\n"); demo_mqtt_stop(&mqtt_handle); return -1; }
步驟二:配置功能
調用aiot_subdev_setopt,配置以下功能。
關聯MQTT連接的句柄。
重要在配置網關與子設備功能參數前,請確保已配置網關的設備認證信息,具體操作,請參見MQTT配置連接參數。
示例代碼:
aiot_subdev_setopt(subdev_handle, AIOT_SUBDEVOPT_MQTT_HANDLE, mqtt_handle);
相關參數:
配置項
示例
說明
AIOT_SUBDEVOPT_MQTT_HANDLE
mqtt_handle
網關與子設備功能的請求基于MQTT連接,通過該配置項,關聯MQTT連接句柄。
配置網關與子設備功能的消息回調。
配置消息回調函數。
示例代碼:
aiot_subdev_setopt(subdev_handle, AIOT_SUBDEVOPT_RECV_HANDLER, demo_subdev_recv_handler);
相關參數:
配置項
示例值
說明
AIOT_SUBDEVOPT_RECV_HANDLER
demo_subdev_recv_handler
當設備收到來自物聯網平臺的網關與子設備的相關消息時,觸發該回調函數,根據其設置,執行對應的處理。
定義消息回調函數。
關于消息的Alink數據格式,請參見管理拓撲關系和子設備上下線。
void demo_subdev_recv_handler(void *handle, const aiot_subdev_recv_t *packet, void *user_data) { switch (packet->type) { case AIOT_SUBDEVRECV_TOPO_ADD_REPLY: case AIOT_SUBDEVRECV_TOPO_DELETE_REPLY: case AIOT_SUBDEVRECV_TOPO_GET_REPLY: case AIOT_SUBDEVRECV_BATCH_LOGIN_REPLY: case AIOT_SUBDEVRECV_BATCH_LOGOUT_REPLY: case AIOT_SUBDEVRECV_SUB_REGISTER_REPLY: case AIOT_SUBDEVRECV_PRODUCT_REGISTER_REPLY: { printf("msgid : %d\n", packet->data.generic_reply.msg_id); printf("code : %d\n", packet->data.generic_reply.code); printf("product key : %s\n", packet->data.generic_reply.product_key); printf("device name : %s\n", packet->data.generic_reply.device_name); printf("message : %s\n", (packet->data.generic_reply.message == NULL)?("NULL"):(packet->data.generic_reply.message)); printf("data : %s\n", packet->data.generic_reply.data); } break; case AIOT_SUBDEVRECV_TOPO_CHANGE_NOTIFY: { printf("msgid : %d\n", packet->data.generic_notify.msg_id); printf("product key : %s\n", packet->data.generic_notify.product_key); printf("device name : %s\n", packet->data.generic_notify.device_name); printf("params : %s\n", packet->data.generic_notify.params); } break; default: { } } }
步驟三:添加拓撲關系
獲取子設備的認證信息。
為子設備創建對應的產品和設備,創建產品時,節點類型選擇為網關子設備。例如,創建子設備對應產品,并添加4個子設備。
產品名稱
ProductKey
DeviceName
DeviceSecret
ProductSecret
LightSwitchSD
a13FN******
LightSwitch_SubDev_01
768XBgQwgOakz3K4uhOiLeeh9x******
y7GSILD480******
LightSwitch_SubDev_02
iwTZrbjbgNVChfuJkihjE5asek******
LightSwitch_SubDev_03
fdutq35iKMYdcWWBuIINY26hsN******
LightSwitch_SubDev_04
HCKv50YqgwdKhy5cE0Vz4aydmK******
定義子設備認證信息的變量
g_subdev
。示例代碼為預置4個子設備的認證信息,在實際業務中,需自行編寫代碼,定義獲取子設備認證信息的方式。例如:
- 在網關與子設備之間定義協議,實現網關發現子設備,獲取子設備的設備證書。該協議由網關廠商與子設備廠商自行定義。
- 網關廠商可以在網關上提供某種配置方式,預置子設備的證書信息。該功能由網關廠商自行實現。
aiot_subdev_dev_t g_subdev[] = { { "a13FN******", "LightSwitch_SubDev_01", "768XBgQwgOakz3K4uhOiLeeh9x******", "y7GSILD480******" }, { "a13FN******", "LightSwitch_SubDev_02", "iwTZrbjbgNVChfuJkihjE5asek******", "y7GSILD480******" }, { "a13FN******", "LightSwitch_SubDev_03", "fdutq35iKMYdcWWBuIINY26hsN******", "y7GSILD480******" }, { "a13FN******", "LightSwitch_SubDev_04", "HCKv50YqgwdKhy5cE0Vz4aydmK******", "y7GSILD480******" } };
調用aiot_subdev_send_topo_add,向物聯網平臺,發送添加子設備與網關設備的拓撲關系請求。
res = aiot_subdev_send_topo_add(subdev_handle, g_subdev, sizeof(g_subdev)/sizeof(aiot_subdev_dev_t)); if (res < STATE_SUCCESS) { printf("aiot_subdev_send_topo_add failed, res: -0x%04X\n", -res); aiot_subdev_deinit(&subdev_handle); demo_mqtt_stop(&mqtt_handle); return -1; }
可選:當網關設備不再代理子設備接收物聯網平臺的消息時,您可以調用aiot_subdev_send_topo_delete,刪除子設備與網關設備的拓撲關系。
aiot_subdev_send_topo_delete(subdev_handle, g_subdev, sizeof(g_subdev)/sizeof(aiot_subdev_dev_t)); if (res < STATE_SUCCESS) { printf("aiot_subdev_send_topo_delete failed, res: -0x%04X\n", -res); aiot_subdev_deinit(&subdev_handle); demo_mqtt_stop(&mqtt_handle); return -1; }
步驟四:登錄子設備
調用aiot_subdev_send_batch_login,向物聯網平臺發送子設備批量登錄的請求,通過建立的拓撲關系,執行登錄操作后,子設備將變更為在線狀態。
aiot_subdev_send_batch_login(subdev_handle, g_subdev, sizeof(g_subdev)/sizeof(aiot_subdev_dev_t)); if (res < STATE_SUCCESS) { printf("aiot_subdev_send_batch_login failed, res: -0x%04X\n", -res); aiot_subdev_deinit(&subdev_handle); demo_mqtt_stop(&mqtt_handle); return -1; }
可選:如果需要主動下線設備,您可以調用aiot_subdev_send_batch_logout,向物聯網平臺發送斷開連接的請求,物聯網平臺接收請求消息后,執行下線操作,子設備將變更為離線狀態。
重要通過該接口,物聯網平臺更新子設備狀態為離線,避免網關收到發送給子設備的消息。
aiot_subdev_send_batch_logout(subdev_handle, g_subdev, sizeof(g_subdev)/sizeof(aiot_subdev_dev_t)); if (res < STATE_SUCCESS) { printf("aiot_subdev_send_batch_logout failed, res: -0x%04X\n", -res); aiot_subdev_deinit(&subdev_handle); demo_mqtt_stop(&mqtt_handle); return -1; }
子設備登錄或登出后,物聯網平臺對發送子設備的消息,根據其對應狀態,執行以下操作:
如果子設備離線,物聯網平臺發送給子設備的
QoS=0
消息立即丟棄。如果子設備在線,物聯網平臺將子設備的消息發送給對應網關設備,然后由網關設備將子設備的消息轉發給子設備。
步驟五:子設備訂閱Topic
子設備通過網關設備接入物聯網平臺后,可以調用aiot_mqtt_sub,訂閱子設備的Topic,接收對應Topic的消息。
訂閱Topic時,注意區分子設備和網關設備的ProductKey和DeviceName,確保訂閱所需設備的Topic。
示例代碼:
{ char *sub_topic = "/a13FN******/LightSwitch_SubDev_01/user/get"; res = aiot_mqtt_sub(mqtt_handle, sub_topic, NULL, 1, NULL); if (res < 0) { printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res); return -1; } }
相關參數:
參數
示例
說明
sub_topic
/a13FN******/LightSwitch_SubDev_01/user/get
擁有訂閱權限的Topic。其中:
a13FN******
為子設備的ProductKey。LightSwitch_SubDev_01
為子設備的DeviceName。
本示例為子設備默認的自定義Topic,設備通過該Topic,可接收物聯網平臺的消息。
關于Topic的更多信息,請參見什么是Topic。
步驟六:子設備發布消息
調用aiot_mqtt_pub,向子設備的指定Topic發送消息。
示例代碼:
{ char *pub_topic = "/a13FN******/LightSwitch_SubDev_01/user/update"; char *pub_payload = "{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}"; res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0); if (res < 0) { printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res); return -1; } }
相關參數:
參數
示例
說明
pub_topic
/a13FN******/LightSwitch_SubDev_01/user/update
擁有發布權限的Topic。其中:
a13FN******
為子設備的ProductKey。LightSwitch_SubDev_01
為子設備的DeviceName。
本示例為子設備默認的自定義Topic,設備通過該Topic向物聯網平臺發送消息。
關于Topic的更多信息,請參見什么是Topic。
pub_payload
{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}
步驟七:斷開網關連接
MQTT接入常應用于長連接的設備,程序通常不會運行至此。
例程的主線程任務為配置參數并成功建立連接。連接建立后,主線程可進入休眠。
調用aiot_mqtt_disconnect,向物聯網平臺發送斷開連接的報文,然后斷開網絡連接。
res = aiot_mqtt_disconnect(mqtt_handle);
if (res < STATE_SUCCESS) {
aiot_mqtt_deinit(&mqtt_handle);
printf("aiot_mqtt_disconnect failed: -0x%04X\n", -res);
return -1;
}
步驟八:退出程序
調用aiot_subdev_deinit,銷毀subdev
客戶端實例,釋放資源。
res = aiot_subdev_deinit(&subdev_handle);
if (res < STATE_SUCCESS) {
printf("aiot_subdev_deinit failed: -0x%04X\n", res);
}
后續步驟
例程文件配置完成后,需進行編譯,生成可執行文件../output/subdev-basic-demo。
更多信息,請參見編譯與運行。
關于運行結果的詳細說明,請參見運行日志。