全部產品
Search
文件中心

:使用樣本

更新時間:Jun 30, 2024

./demos/shadow_basic_demo.c展示裝置影子功能。

背景資訊

  • 裝置影子功能的更多資訊,請參見概述

  • 裝置影子功能基於MQTT接入,開發過程中涉及MQTT接入的代碼說明,請參見MQTT接入

步驟一:初始化

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

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

        aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
        aiot_state_set_logcb(demo_state_logcb);
  3. 調用aiot_shadow_init,建立Shadow
        shadow_handle = aiot_shadow_init();
        if (shadow_handle == NULL) {
            printf("aiot_shadow_init failed\n");
            return -1;
        }

步驟二:配置功能

調用aiot_shadow_setopt,配置以下功能。

  1. 關聯MQTT串連的控制代碼。
    重要 配置裝置影子功能參數前,請確保已配置裝置認證資訊等相關參數。具體操作,請參見MQTT配置串連參數
    •     aiot_shadow_setopt(shadow_handle, AIOT_SHADOWOPT_MQTT_HANDLE, mqtt_handle);
    • 配置項樣本值說明
      AIOT_SHADOWOPT_MQTT_HANDLEmqtt_handle裝置影子功能的請求基於MQTT串連,通過該配置項,關聯MQTT串連控制代碼。

  2. 配置訊息回調
    •     aiot_shadow_setopt(shadow_handle, AIOT_SHADOWOPT_RECV_HANDLER, (void *)demo_shadow_recv_handler);
    • 配置項樣本值說明
      AIOT_SHADOWOPT_RECV_HANDLERdemo_shadow_recv_handler接收裝置影子相關訊息時,調用該函數。

步驟三:裝置主動上報狀態

裝置線上時,主動上報裝置狀態到影子,應用程式主動擷取裝置影子狀態。

  1. 裝置調用aiot_shadow_send,向物聯網平台上報最新狀態到影子。
    上報狀態時,需注意:
    • 上報狀態訊息的資料結構類型為aiot_shadow_msg_t,是aiot_shadow_send()的入參。
    • 上報狀態的訊息類型為AIOT_SHADOWMSG_UPDATE
    int32_t demo_update_shadow(void *shadow_handle, char *reported_data, int64_t version)
    {
        aiot_shadow_msg_t message;
    
        memset(&message, 0, sizeof(aiot_shadow_msg_t));
        message.type = AIOT_SHADOWMSG_UPDATE;
        message.data.update.reported = reported_data;
        message.data.update.version = version;
    
        return aiot_shadow_send(shadow_handle, &message);
    }
  2. 設定上報狀態訊息的內容。
    •         res = demo_update_shadow(shadow_handle, "{\"LightSwitch\":1}", 0);
              if (res < 0) {
                  printf("demo_delete_shadow_report failed, res = -0x%04x\r\n", -res);
              }
    • 樣本訊息內容說明:
      樣本Alink格式說明
      {
          "LightSwitch": 1
      }
      {
        "method": "update", 
        "state": {
          "reported": {
            "LightSwitch": 1
          }
        }, 
        "version": 0
      }
      上報的訊息的內容為JSON格式,是Alink格式資料中state的值。詳細說明,請參見裝置主動上報狀態

      範例程式碼的訊息內容為:

      • 將屬性LightSwitch設定為1
      • 將版本號碼設定為0
        說明
        • 後續操作的版本號碼遞增, 否則物聯網平台將返回錯誤。
        • 如果將版本號碼設定為-1, 物聯網平台則清空裝置影子資料,並將版本號碼更新為0
  3. 物聯網平台接收到裝置影子的訊息後,更新影子檔案。然後,向裝置返回應答報文。
  4. 裝置接收應答報文後,觸發回呼函數demo_shadow_recv_handler

    您可以參考以下內容,編寫回呼函數的處理邏輯:

    • 應答報文的資料結構類型為aiot_shadow_recv_t,是回呼函數的入參。
    • 應答報文訊息的類型為AIOT_SHADOWRECV_GENERIC_REPLY
    • 以下是應答報文樣本及其Alink資料格式:
      樣本Alink格式說明
      {
          "status":"success",
          "version":0
      }
      {
        "method": "reply", 
        "payload": {
          "status": "success", 
          "version": 0
        }, 
        "timestamp": 1626317187
      }
      應答報文的內容是Alink資料中payload的值。

      樣本訊息表示上報狀態成功。

    • 範例程式碼僅做列印處理。
    void demo_shadow_recv_handler(void *handle, const aiot_shadow_recv_t *recv, void *userdata)
    {
        printf("demo_shadow_recv_handler, type = %d, productKey = %s, deviceName = %s\r\n",
                recv->type, recv->product_key, recv->device_name);
    
        switch (recv->type) {
    
            case AIOT_SHADOWRECV_GENERIC_REPLY: {
                const aiot_shadow_recv_generic_reply_t *generic_reply = &recv->data.generic_reply;
    
                printf("payload = \"%.*s\", status = %s, timestamp = %ld\r\n",
                       generic_reply->payload_len,
                       generic_reply->payload,
                       generic_reply->status,
                       (unsigned long)generic_reply->timestamp);
            }
    ……
    ……
            default:
                break;
        }
    }

步驟四:應用程式改變裝置狀態

您可以通過應用程式,或登入物聯網平台,向裝置影子發送期望屬性,最終實現改變裝置狀態。

  1. 下發期望狀態給裝置影子。
    • 您可以開發物聯網平台雲端應用程式,調用API下發裝置影子期望屬性,詳細說明,請參見UpdateDeviceShadow
    • 您可以在物聯網平台的裝置詳情頁,直接下發裝置影子期望屬性,具體操作,請參見查看與更新裝置影子
  2. 物聯網平台根據下發的期望狀態訊息,更新影子內容。然後,下發該影子內容至裝置。
  3. 裝置接收影子檔案後,觸發回呼函數demo_shadow_recv_handler
    重要 如果裝置不線上,具體操作,請參見步驟五:裝置主動擷取裝置影子內容
    您可以參考以下內容,編寫回呼函數的處理邏輯:
    • 下發的期望狀態訊息的資料結構類型為aiot_shadow_recv_t,是回呼函數的入參。
    • 期望狀態的訊息類型為AIOT_SHADOWRECV_CONTROL
    • 以下是期望狀態訊息樣本及其Alink資料格式:
      樣本Alink格式說明
      {
          "state": {
              "desired": {
                  "LightSwitch": 0
              }
          },
          "metadata": {
              "desired": {
                  "LightSwitch": {
                      "timestamp": 1626319658
                  }
              }
          }
      }
      {
        "method": "control", 
        "payload": { 
         "state": {
              "desired": {
                  "LightSwitch": 0
              }
          },
          "metadata": {
              "desired": {
                  "LightSwitch": {
                      "timestamp": 1626319658 
             }
            }
          }
        }, 
        "version": 2, 
        "timestamp": 1469564576
      }
      期望狀態訊息的的內容是Alink資料中payload的值。

      樣本訊息為設定LightSwitch的期望屬性值為0

    • 範例程式碼僅做列印處理。
    void demo_shadow_recv_handler(void *handle, const aiot_shadow_recv_t *recv, void *userdata)
    {
        printf("demo_shadow_recv_handler, type = %d, productKey = %s, deviceName = %s\r\n",
                recv->type, recv->product_key, recv->device_name);
    
        switch (recv->type) {
    ……
    ……
            case AIOT_SHADOWRECV_CONTROL: {
                const aiot_shadow_recv_control_t *control = &recv->data.control;
    
                printf("payload = \"%.*s\", version = %ld\r\n",
                       control->payload_len,
                       control->payload,
                       (unsigned long)control->version);
            }
    ……
    ……
            default:
                break;
        }
    }
  4. 裝置更新狀態後,上報最新的狀態至裝置影子,並處理應答報文。
    具體操作,請參見步驟三:裝置主動上報狀態
  5. 上報最新的狀態後,調用aiot_shadow_send,刪除期望屬性。
    請求刪除期望屬性時,需注意:
    • 刪除期望屬性訊息的資料結構類型為aiot_shadow_msg_t,是aiot_shadow_send()的入參。
    • 訊息的類型為AIOT_SHADOWMSG_CLEAN_DESIRED
    • 範例程式碼刪除了期望屬性的全部內容,並設定版本號碼為1
    int32_t demo_clean_shadow_desired(void *shadow_handle, int64_t version)
    {
        aiot_shadow_msg_t message;
    
        memset(&message, 0, sizeof(aiot_shadow_msg_t));
        message.type = AIOT_SHADOWMSG_CLEAN_DESIRED;
        message.data.clean_desired.version = version;
    
        return aiot_shadow_send(shadow_handle, &message);
    }
    ……
    ……
            res = demo_clean_shadow_desired(shadow_handle, 1);
            if (res < 0) {
                printf("demo_clean_shadow_desired failed, res = -0x%04x\r\n", -res);
            }
  6. 刪除屬性的請求發送後,物聯網平台返回應答報文,觸發回呼函數demo_shadow_recv_handler
    具體操作,請參見配置應答報文的回呼函數

步驟五:裝置主動擷取裝置影子內容

若應用程式發送指令時,裝置離線。裝置再次上線後,將主動擷取裝置影子內容。

  1. 裝置調用aiot_shadow_send,向物聯網平台發送查詢指令,擷取裝置影子內容。
    查詢指令的訊息類型為AIOT_SHADOWMSG_GET
    int32_t demo_get_shadow(void *shadow_handle)
    {
        aiot_shadow_msg_t message;
    
        memset(&message, 0, sizeof(aiot_shadow_msg_t));
        message.type = AIOT_SHADOWMSG_GET;
    
        return aiot_shadow_send(shadow_handle, &message);
    }
    ……
    ……
            res = demo_get_shadow(shadow_handle);
            if (res < 0) {
                printf("demo_get_shadow failed, res = -0x%04x\r\n", -res);
            }
  2. 物聯網平台收到查詢指令後,返回查詢結果。裝置接收返回結果後,觸發回呼函數demo_shadow_recv_handler
    您可以參考以下內容,編寫回呼函數的處理邏輯:
    • 回呼函數處理訊息的資料結構類型為aiot_shadow_recv_t,是回呼函數的入參。
    • 訊息的類型為AIOT_SHADOWRECV_GET_REPLY
    • 以下是查詢後返回的訊息樣本及其Alink資料格式:
      樣本Alink格式說明
      {
          "status": "success",
          "state": {
              "reported": {
      
              }
          },
          "metadata": {
              "reported": {
      
              }
          }
      }
      {
        "method": "reply", 
        "payload": {
          "status": "success",
          "state": {
              "reported": {
      
              }
          },
          "metadata": {
              "reported": {
      
              }
          }
      }, 
        "version": 5, 
        "timestamp": 1626320690
      }
      擷取屬性訊息的內容是Alink資料中payload的值。

      樣本訊息表示請求發送成功,擷取的訊息值未空,未上報過訊息。

    • 範例程式碼僅做列印處理。
    void demo_shadow_recv_handler(void *handle, const aiot_shadow_recv_t *recv, void *userdata)
    {
        printf("demo_shadow_recv_handler, type = %d, productKey = %s, deviceName = %s\r\n",
                recv->type, recv->product_key, recv->device_name);
    
        switch (recv->type) {
    ……
    ……
            case AIOT_SHADOWRECV_GET_REPLY: {
                const aiot_shadow_recv_get_reply_t *get_reply = &recv->data.get_reply;
    
                printf("payload = \"%.*s\", version = %ld\r\n",
                       get_reply->payload_len,
                       get_reply->payload,
                       (unsigned long)get_reply->version);
            }
            default:
                break;
        }
    }

步驟六:裝置主動刪除影子屬性

若裝置端已經是最新狀態,裝置端可以主動發送指令,刪除裝置影子中儲存的某條屬性狀態。

  1. 裝置調用aiot_shadow_send,向物聯網平台發送刪除指令,刪除裝置影子中的指定屬性。
    發送刪除指令時,需注意:
    • 刪除指令的資料結構類型為aiot_shadow_msg_t,是aiot_shadow_send()的入參。
    • 刪除指令的訊息類型為AIOT_SHADOWMSG_DELETE_REPORTED
    int32_t demo_delete_shadow_report(void *shadow_handle, char *reported, int64_t version)
    {
        aiot_shadow_msg_t message;
    
        memset(&message, 0, sizeof(aiot_shadow_msg_t));
        message.type = AIOT_SHADOWMSG_DELETE_REPORTED;
        message.data.delete_reporte.reported = reported;
        message.data.delete_reporte.version = version;
    
        return aiot_shadow_send(shadow_handle, &message);
    }
  2. 設定刪除指令的內容。
    •         res = demo_delete_shadow_report(shadow_handle, "{\"LightSwitch\":\"null\"}", 2);
              if (res < 0) {
                  printf("demo_delete_shadow_report failed, res = -0x%04x\r\n", -res);
              }
    • 樣本訊息內容說明:
      樣本Alink格式說明
      "{\"LightSwitch\":\"null\"}", 2
      {
        "method": "delete", 
        "state": {
          "reported": {
            "LightSwitch": "null", 
          }
        }, 
        "version": 2
      }
      刪除指令訊息的內容為JSON格式,是Alink格式資料中state的值。詳細說明,請參見裝置主動刪除影子屬性

      範例程式碼的訊息內容為:

      • 將屬性LightSwitch設定為null,表示清除裝置影子所有資料。
      • 將版本號碼設定為2
  3. 物聯網平台收到刪除指令後,返回應答報文。裝置接收報文後,觸發回呼函數demo_shadow_recv_handler
    具體操作,請參見配置應答報文的回呼函數

步驟七:退出程式

調用aiot_shadow_deinit,銷毀Shadow

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

後續步驟

  • 常式檔案配置完成後,需進行編譯,產生可執行檔./output/shadow-basic-demo
    重要
    • 配置Demo檔案時,請根據測試情境,取消上報狀態、擷取屬性、刪除期望或上報屬性的相關代碼兩邊的注釋符號(/**/),並根據情境更換版本號碼。
    • 更新版本號碼時,需注意:
      • 後續操作的版本號碼遞增, 否則物聯網平台將返回錯誤。
      • 如果將版本號碼設定為-1, 物聯網平台則清空裝置影子資料,並將版本號碼更新為0
  • 作業記錄