全部產品
Search
文件中心

:使用樣本

更新時間:Jun 30, 2024

./demos/fota_posix_demo.c協助您實現子裝置通過網關接入物聯網平台。

背景資訊

  • 網關與子裝置的更多資訊,請參見概述
  • 子裝置的網關裝置需與物聯網平台保持長串連,接入方法與直連裝置一致。更多資訊,請參見MQTT接入概述

    本文樣本中,網關裝置的身份認證資訊如下:

    ProductKeyDeviceNameDeviceSecret
    a18wP******LightSwitchGWuwMTmVAMnGGHaAkqmeDY6cHxxB******

步驟一:初始化

  1. 添加標頭檔。
    ……
    ……
    
    #include "aiot_subdev_api.h"

  2. 配置底層依賴和日誌輸出。

        aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
        aiot_state_set_logcb(demo_state_logcb);
  3. 調用aiot_subdev_init,建立subdev
        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,配置以下功能。

  1. 關聯MQTT串連的控制代碼
  2. 配置網關與子裝置功能的訊息回調
  1. 關聯MQTT串連的控制代碼。
    重要 在配置網關與子裝置功能參數前,請確保已配置網關的裝置認證資訊,具體操作,請參見MQTT配置串連參數
    •     aiot_subdev_setopt(subdev_handle, AIOT_SUBDEVOPT_MQTT_HANDLE, mqtt_handle);
    • 配置項樣本說明
      AIOT_SUBDEVOPT_MQTT_HANDLEmqtt_handle網關與子裝置功能的請求基於MQTT串連,通過該配置項,關聯MQTT串連控制代碼。

  2. 配置網關與子裝置功能的訊息回調。
    1. 配置訊息回呼函數。
      •     aiot_subdev_setopt(subdev_handle, AIOT_SUBDEVOPT_RECV_HANDLER, demo_subdev_recv_handler);
      • 配置項樣本值說明
        AIOT_SUBDEVOPT_RECV_HANDLERdemo_subdev_recv_handler當裝置收到來自物聯網平台的網關與子裝置的相關訊息時,觸發該回呼函數,根據其設定,執行對應的處理。

    2. 定義訊息回呼函數。
      關於訊息的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: {
      
              }
          }
      }

步驟三:添加拓撲關係

  1. 擷取子裝置的認證資訊。
    為子裝置建立對應的產品和裝置,建立產品時,節點類型選擇為網關子裝置例如,建立子裝置對應產品,並添加4個子裝置。
    產品名稱ProductKeyDeviceNameDeviceSecretProductSecret
    LightSwitchSDa13FN******LightSwitch_SubDev_01768XBgQwgOakz3K4uhOiLeeh9x******y7GSILD480******
    LightSwitch_SubDev_02iwTZrbjbgNVChfuJkihjE5asek******
    LightSwitch_SubDev_03fdutq35iKMYdcWWBuIINY26hsN******
    LightSwitch_SubDev_04HCKv50YqgwdKhy5cE0Vz4aydmK******

    具體操作,請參見建立產品建立裝置

  2. 定義子裝置認證資訊的變數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******"
        }
    };
  3. 調用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;
        }
  4. 可選:當網關裝置不再代理子裝置接收物聯網平台的訊息時,您可以調用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;
         }

步驟四:登入子裝置

  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;
        }
  2. 可選:如果需要主動下線裝置,您可以調用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時,注意區分子裝置和網關裝置的ProductKeyDeviceName,確保訂閱所需裝置的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
    其中:
    • a13FN******為子裝置的ProductKey。
    • LightSwitch_SubDev_01為子裝置的DeviceName。

    本樣本為子裝置預設的自訂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

    pub_payload{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}

    上報至物聯網平台的訊息內容。

    由於樣本訊息的Topic類型為自訂,因此資料格式可自訂。

    關於資料格式的更多資訊,請參見資料格式

步驟七:斷開網關串連

說明

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);
    }

後續步驟