開始使用結束裝置 SDK - 的受管整合 AWS IoT Device Management

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

開始使用結束裝置 SDK

請依照下列步驟,在 Linux 裝置上執行結束裝置 SDK。本節會引導您完成環境設定、網路組態、硬體函數實作和端點組態。

重要

examples 目錄中的示範應用程式及其 中的平台抽象層 (PAL) 實作僅供platform/posix參考。請勿在生產環境中使用這些項目。

請仔細檢閱下列程序的每個步驟,以確保適當的裝置與受管整合整合。

整合結束裝置 SDK
  1. 設定 Amazon EC2 執行個體

    登入 並使用 Amazon Linux AMI AWS Management Console 啟動 Amazon EC2 執行個體。 Amazon EC2 請參閱《Amazon Elastic Container Registry 使用者指南》中的 Amazon EC2 入門https://docs.aws.amazon.com/AmazonECR/latest/userguide/

  2. 設定建置環境

    在 Amazon Linux 2023/x86_64 上建置程式碼做為您的開發主機。安裝必要的建置相依性:

    dnf install make gcc gcc-c++ cmake
  3. (選用) 設定網路

    終端裝置 SDK 最適合與實體硬體搭配使用。如果使用 Amazon EC2,請勿遵循此步驟。

    如果您在使用範例應用程式之前未使用 Amazon EC2,請初始化網路並將您的裝置連線至可用的 Wi-Fi 網路。在裝置佈建之前完成網路設定:

    /* Provisioning the device PKCS11 with claim credential. */ status = deviceCredentialProvisioning();
  4. 設定佈建參數
    注意

    遵循佈建者取得宣告憑證和私有金鑰,然後再繼續。

    example/project_name/device_config.sh 使用下列佈建參數修改組態檔案:

    佈建參數
    巨集參數 描述 如何取得此資訊
    IOTMI_ROOT_CA_PATH 根 CA 憑證檔案。 您可以從AWS IoT Core 開發人員指南中的下載 Amazon 根 CA 憑證區段下載此檔案。
    IOTMI_CLAIM_CERTIFICATE_PATH 宣告憑證檔案的路徑。 若要取得宣告憑證和私有金鑰,請使用 CreateProvisioningProfile API 建立佈建設定檔。如需說明,請參閱建立佈建設定檔
    IOTMI_CLAIM_PRIVATE_KEY_PATH 宣告私有金鑰檔案的路徑。
    IOTMI_MANAGEDINTEGRATIONS_ENDPOINT 受管整合的端點 URL。 若要取得受管整合端點,請使用 RegisterCustomEndpoint API。如需說明,請參閱註冊自訂端點
    IOTMI_MANAGEDINTEGRATIONS_ENDPOINT_PORT 受管整合端點的連接埠號碼 根據預設,連接埠 8883 用於 MQTT 發佈和訂閱操作。連接埠 443 設定為裝置使用的 Application Layer Protocol Negotiation (ALPN) TLS 延伸。
  5. 建置並執行示範應用程式

    本節示範兩個 Linux 示範應用程式:簡單的安全攝影機和空氣淨化器,兩者都使用 CMake 做為建置系統。

    1. 簡單安全攝影機應用程式

      若要建置和執行應用程式,請執行下列命令:

      >cd <path-to-code-drop> # If you didn't generate cluster code earlier >(cd codegen && poetry run poetry install --no-root && ./gen-data-model-api.sh) >mkdir build >cd build >cmake .. >cmake —build . >./examples/iotmi_device_sample_camera/iotmi_device_sample_camera

      此示範為具有 RTC 工作階段控制器和錄製叢集的模擬攝影機實作低階 C-Functions。在執行佈建者工作流程之前完成 中提到的流程。

      示範應用程式的範例輸出:

      [2406832727][MAIN][INFO] ======= Device initialization and WIFI provisioning ======= [2406832728][MAIN][INFO] fleetProvisioningTemplateName: XXXXXXXXXXX [2406832728][MAIN][INFO] managedintegrationsEndpoint: XXXXXXXXX.account-prefix-ats.iot.region.amazonaws.com [2406832728][MAIN][INFO] pDeviceSerialNumber: XXXXXXXXXXXX [2406832728][MAIN][INFO] universalProductCode: XXXXXXXXXXXX [2406832728][MAIN][INFO] rootCertificatePath: XXXXXXXXX [2406832728][MAIN][INFO] pClaimCertificatePath: XXXXXXXX [2406832728][MAIN][INFO] pClaimKeyPath: XXXXXXXXXXXXXXXXX [2406832728][MAIN][INFO] deviceInfo.serialNumber XXXXXXXXXXXX [2406832728][MAIN][INFO] deviceInfo.universalProductCode XXXXXXXXXXXXXXX [2406832728][PKCS11][INFO] PKCS #11 successfully initialized. [2406832728][MAIN][INFO] ============= Start certificate provisioning ============= [2406832728][PKCS11][INFO] ======== Loading Root CA and claim credentials through PKCS#11 interface ======== [2406832728][PKCS11][INFO] Writing certificate into label "Root Cert". [2406832728][PKCS11][INFO] Creating a 0x1 type object. [2406832728][PKCS11][INFO] Writing certificate into label "Claim Cert". [2406832728][PKCS11][INFO] Creating a 0x1 type object. [2406832728][PKCS11][INFO] Creating a 0x3 type object. [2406832728][MAIN][INFO] ======== Fleet-provisioning-by-Claim ======== [2025-01-02 01:43:11.404995144][iotmi_device_sdkLog][INFO] [2406832728][MQTT_AGENT][INFO] [2025-01-02 01:43:11.405106991][iotmi_device_sdkLog][INFO] Establishing a TLS session to XXXXXXXXXXXXXXX.account-prefix-ats.iot.region.amazonaws.com [2025-01-02 01:43:11.405119166][iotmi_device_sdkLog][INFO] [2025-01-02 01:43:11.844812513][iotmi_device_sdkLog][INFO] [2406833168][MQTT_AGENT][INFO] [2025-01-02 01:43:11.844842576][iotmi_device_sdkLog][INFO] TLS session connected [2025-01-02 01:43:11.844852105][iotmi_device_sdkLog][INFO] [2025-01-02 01:43:12.296421687][iotmi_device_sdkLog][INFO] [2406833620][MQTT_AGENT][INFO] [2025-01-02 01:43:12.296449663][iotmi_device_sdkLog][INFO] Session present: 0. [2025-01-02 01:43:12.296458997][iotmi_device_sdkLog][INFO] [2025-01-02 01:43:12.296467793][iotmi_device_sdkLog][INFO] [2406833620][MQTT_AGENT][INFO] [2025-01-02 01:43:12.296476275][iotmi_device_sdkLog][INFO] MQTT connect with clean session. [2025-01-02 01:43:12.296484350][iotmi_device_sdkLog][INFO] [2025-01-02 01:43:13.171056119][iotmi_device_sdkLog][INFO] [2406834494][FLEET_PROVISIONING][INFO] [2025-01-02 01:43:13.171082442][iotmi_device_sdkLog][INFO] Received accepted response from Fleet Provisioning CreateKeysAndCertificate API. [2025-01-02 01:43:13.171092740][iotmi_device_sdkLog][INFO] [2025-01-02 01:43:13.171122834][iotmi_device_sdkLog][INFO] [2406834494][FLEET_PROVISIONING][INFO] [2025-01-02 01:43:13.171132400][iotmi_device_sdkLog][INFO] Received privatekey and certificate with Id: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [2025-01-02 01:43:13.171141107][iotmi_device_sdkLog][INFO] [2406834494][PKCS11][INFO] Creating a 0x3 type object. [2406834494][PKCS11][INFO] Writing certificate into label "Device Cert". [2406834494][PKCS11][INFO] Creating a 0x1 type object. [2025-01-02 01:43:18.584615126][iotmi_device_sdkLog][INFO] [2406839908][FLEET_PROVISIONING][INFO] [2025-01-02 01:43:18.584662031][iotmi_device_sdkLog][INFO] Received accepted response from Fleet Provisioning RegisterThing API. [2025-01-02 01:43:18.584671912][iotmi_device_sdkLog][INFO] [2025-01-02 01:43:19.100030237][iotmi_device_sdkLog][INFO] [2406840423][FLEET_PROVISIONING][INFO] [2025-01-02 01:43:19.100061720][iotmi_device_sdkLog][INFO] Fleet-provisioning iteration 1 is successful. [2025-01-02 01:43:19.100072401][iotmi_device_sdkLog][INFO] [2406840423][MQTT][ERROR] MQTT Connection Disconnected Successfully [2025-01-02 01:43:19.216938181][iotmi_device_sdkLog][INFO] [2406840540][MQTT_AGENT][INFO] [2025-01-02 01:43:19.216963713][iotmi_device_sdkLog][INFO] MQTT agent thread leaves thread loop for iotmiDev_MQTTAgentStop. [2025-01-02 01:43:19.216973740][iotmi_device_sdkLog][INFO] [2406840540][MAIN][INFO] iotmiDev_MQTTAgentStop is called to break thread loop function. [2406840540][MAIN][INFO] Successfully provision the device. [2406840540][MAIN][INFO] Client ID : XXXXXXXXXXXXXXXXXXXX_XXXXXXXXXXXXXXXXXXXXXXXX [2406840540][MAIN][INFO] Managed thing ID : XXXXXXXXXXXXXXXXXXXXXXX [2406840540][MAIN][INFO] ======================== application loop ================= [2025-01-02 01:43:19.217094828][iotmi_device_sdkLog][INFO] [2406840540][MQTT_AGENT][INFO] [2025-01-02 01:43:19.217124600][iotmi_device_sdkLog][INFO] Establishing a TLS session to XXXXXXXXX.account-prefix-ats.iot.region.amazonaws.com:8883 [2025-01-02 01:43:19.217138724][iotmi_device_sdkLog][INFO] [2406840540][Cluster OnOff][INFO] exampleOnOffInitCluster() for endpoint#1 [2406840540][MAIN][INFO] Press Ctrl+C when you finish testing... [2406840540][Cluster ActivatedCarbonFilterMonitoring][INFO] exampleActivatedCarbonFilterMonitoringInitCluster() for endpoint#1 [2406840540][Cluster AirQuality][INFO] exampleAirQualityInitCluster() for endpoint#1 [2406840540][Cluster CarbonDioxideConcentrationMeasurement][INFO] exampleCarbonDioxideConcentrationMeasurementInitCluster() for endpoint#1 [2406840540][Cluster FanControl][INFO] exampleFanControlInitCluster() for endpoint#1 [2406840540][Cluster HepaFilterMonitoring][INFO] exampleHepaFilterMonitoringInitCluster() for endpoint#1 [2406840540][Cluster Pm1ConcentrationMeasurement][INFO] examplePm1ConcentrationMeasurementInitCluster() for endpoint#1 [2406840540][Cluster Pm25ConcentrationMeasurement][INFO] examplePm25ConcentrationMeasurementInitCluster() for endpoint#1 [2406840540][Cluster TotalVolatileOrganicCompoundsConcentrationMeasurement][INFO] exampleTotalVolatileOrganicCompoundsConcentrationMeasurementInitCluster() for endpoint#1 [2025-01-02 01:43:19.648185488][iotmi_device_sdkLog][INFO] [2406840971][MQTT_AGENT][INFO] [2025-01-02 01:43:19.648211988][iotmi_device_sdkLog][INFO] TLS session connected [2025-01-02 01:43:19.648225583][iotmi_device_sdkLog][INFO] [2025-01-02 01:43:19.938281231][iotmi_device_sdkLog][INFO] [2406841261][MQTT_AGENT][INFO] [2025-01-02 01:43:19.938304799][iotmi_device_sdkLog][INFO] Session present: 0. [2025-01-02 01:43:19.938317404][iotmi_device_sdkLog][INFO]
    2. 簡單空氣淨化器應用程式

      若要建置和執行應用程式,請執行下列命令:

      >cd <path-to-code-drop> # If you didn't generate cluster code earlier >(cd codegen && poetry run poetry install --no-root && ./gen-data-model-api.sh) >mkdir build >cd build >cmake .. >cmake --build . >./examples/iotmi_device_dm_air_purifier/iotmi_device_dm_air_purifier_demo

      此示範會針對具有 2 個端點和下列支援叢集的模擬空氣淨化器實作低階 C-Functions:

      空氣淨化器端點支援的叢集
      端點 叢集
      端點 #1:空氣淨化器 OnOff
      風扇控制
      HEPA 篩選條件監控

      啟用的碳過濾器監控

      端點 #2:空氣品質感應器 空氣品質
      二氧化碳濃度測量
      Formaldehyde 集中度測量
      Pm25 集中度測量
      Pm1 集中度測量
      揮發性有機化合物總集中度測量

      輸出類似於攝影機示範應用程式,具有不同的支援叢集。

  6. 後續步驟:

    受管整合 終端裝置 SDK 和示範應用程式現在會在您的 Amazon EC2 執行個體上執行。這可讓您在自己的實體硬體上開發和測試應用程式。透過此設定,您可以利用 受管整合服務來控制 AWS IoT 您的裝置。

    1. 開發硬體回呼函數

      實作硬體回呼函數之前,請先了解 API 的運作方式。此範例使用 On/Off OnOff 叢集和 屬性來控制裝置函數。如需 API 詳細資訊,請參閱 低階 C-Functions 的 API 操作

      struct DeviceState { struct iotmiDev_Agent *agent; struct iotmiDev_Endpoint *endpointLight; /* This simulates the HW state of OnOff */ bool hwState; }; /* This implementation for OnOff getter just reads the state from the DeviceState */ iotmiDev_DMStatus exampleGetOnOff(bool *value, void *user) { struct DeviceState *state = (struct DeviceState *)(user); *value = state->hwState; return iotmiDev_DMStatusOk; }
    2. 設定端點和掛接硬體回呼函數

      實作函數之後,請建立端點並註冊您的回呼。完成下列任務:

      1. 建立裝置代理程式。

        1. 在叫用任何其他 SDK 函數iotmiDev_Agent_new()之前,使用 建立裝置代理程式。

        2. 您的組態至少必須包含 thingIdclientId 參數。

        3. 使用 iotmiDev_Agent_initDefaultConfig()函數為佇列大小和最大端點等參數設定合理的預設值。

        4. 使用完資源後,請使用 iotmiDev_Agent_free()函數釋放資源。這可防止記憶體洩漏,並確保應用程式中有適當的資源管理。

      2. 為您要支援的每個叢集結構填入回呼函數指標。

      3. 設定端點並註冊支援的叢集。

        使用 建立端點iotmiDev_Agent_addEndpoint(),這需要:

        1. 唯一的端點 ID。

        2. 描述性端點名稱

        3. 符合 AWS 資料模型定義的一或多個裝置類型。

        4. 建立端點之後,請使用適當的叢集特定註冊函數來註冊叢集。

        5. 每個叢集註冊都需要屬性和命令的回呼函數。系統會將使用者內容指標傳遞至回呼,以在通話之間維持狀態。

      struct DeviceState { struct iotmiDev_Agent * agent; struct iotmiDev_Endpoint *endpoint1; /* OnOff cluster states*/ bool hwState; }; /* This implementation for OnOff getter just reads the state from the DeviceState */ iotmiDev_DMStatus exampleGetOnOff( bool * value, void * user ) { struct DeviceState * state = ( struct DeviceState * ) ( user ); *value = state->hwState; printf( "%s(): state->hwState: %d\n", __func__, state->hwState ); return iotmiDev_DMStatusOk; } iotmiDev_DMStatus exampleGetOnTime( uint16_t * value, void * user ) { *value = 0; printf( "%s(): OnTime is %u\n", __func__, *value ); return iotmiDev_DMStatusOk; } iotmiDev_DMStatus exampleGetStartUpOnOff( iotmiDev_OnOff_StartUpOnOffEnum * value, void * user ) { *value = iotmiDev_OnOff_StartUpOnOffEnum_Off; printf( "%s(): StartUpOnOff is %d\n", __func__, *value ); return iotmiDev_DMStatusOk; } void setupOnOff( struct DeviceState *state ) { struct iotmiDev_clusterOnOff clusterOnOff = { .getOnOff = exampleGetOnOff, .getOnTime = exampleGetOnTime, .getStartUpOnOff = exampleGetStartUpOnOff, }; iotmiDev_OnOffRegisterCluster( state->endpoint1, &clusterOnOff, ( void * ) state); } /* Here is the sample setting up an endpoint 1 with OnOff cluster. Note all error handling code is omitted. */ void setupAgent(struct DeviceState *state) { struct iotmiDev_Agent_Config config = { .thingId = IOTMI_DEVICE_MANAGED_THING_ID, .clientId = IOTMI_DEVICE_CLIENT_ID, }; iotmiDev_Agent_InitDefaultConfig(&config); /* Create a device agent before calling other SDK APIs */ state->agent = iotmiDev_Agent_new(&config); /* Create endpoint#1 */ state->endpoint1 = iotmiDev_Agent_addEndpoint( state->agent, 1, "Data Model Handler Test Device", (const char*[]){ "Camera" }, 1 ); setupOnOff(state); }
    3. 使用任務處理常式來取得任務文件
      1. 啟動對 OTA 應用程式的呼叫:

        static iotmi_JobCurrentStatus_t processOTA( iotmi_JobData_t * pJobData ) { iotmi_JobCurrentStatus_t jobCurrentStatus = JobSucceeded; ... // This function should create OTA tasks jobCurrentStatus = YOUR_OTA_FUNCTION(iotmi_JobData_t * pJobData); ... return jobCurrentStatus; }
      2. 呼叫 iotmi_JobsHandler_start 以初始化任務處理常式。

      3. 呼叫 從受管整合iotmi_JobsHandler_getJobDocument擷取任務文件。

      4. 成功取得任務文件時,請在 processOTA函數中撰寫您的自訂 OTA 操作並傳回 JobSucceeded 狀態。

        static void prvJobsHandlerThread( void * pParam ) { JobsHandlerStatus_t status = JobsHandlerSuccess; iotmi_JobData_t jobDocument; iotmiDev_DeviceRecord_t * pThreadParams = ( iotmiDev_DeviceRecord_t * ) pParam; iotmi_JobsHandler_config_t config = { .pManagedThingID = pThreadParams->pManagedThingID, .jobsQueueSize = 10 }; status = iotmi_JobsHandler_start( &config ); if( status != JobsHandlerSuccess ) { LogError( ( "Failed to start Jobs Handler." ) ); return; } while( !bExit ) { status = iotmi_JobsHandler_getJobDocument( &jobDocument, 30000 ); switch( status ) { case JobsHandlerSuccess: { LogInfo( ( "Job document received." ) ); LogInfo( ( "Job ID: %.*s", ( int ) jobDocument.jobIdLength, jobDocument.pJobId ) ); LogInfo( ( "Job document: %.*s", ( int ) jobDocument.jobDocumentLength, jobDocument.pJobDocument ) ); /* Process the job document */ iotmi_JobCurrentStatus_t jobStatus = processOTA( &jobDocument ); iotmi_JobsHandler_updateJobStatus( jobDocument.pJobId, jobDocument.jobIdLength, jobStatus, NULL, 0 ); iotmiJobsHandler_destroyJobDocument(&jobDocument); break; } case JobsHandlerTimeout: { LogInfo( ( "No job document available. Polling for job document." ) ); iotmi_JobsHandler_pollJobDocument(); break; } default: { LogError( ( "Failed to get job document." ) ); break; } } } while( iotmi_JobsHandler_getJobDocument( &jobDocument, 0 ) == JobsHandlerSuccess ) { /* Before stopping the Jobs Handler, process all the remaining jobs. */ LogInfo( ( "Job document received before stopping." ) ); LogInfo( ( "Job ID: %.*s", ( int ) jobDocument.jobIdLength, jobDocument.pJobId ) ); LogInfo( ( "Job document: %.*s", ( int ) jobDocument.jobDocumentLength, jobDocument.pJobDocument ) ); storeJobs( &jobDocument ); iotmiJobsHandler_destroyJobDocument(&jobDocument); } iotmi_JobsHandler_stop(); LogInfo( ( "Job handler thread end." ) ); }