

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

# 開始使用結束裝置 SDK
<a name="managedintegrations-sdk-device-onboarding"></a>

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

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

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

**整合結束裝置 SDK**

1. <a name="managedintegrations-sdk-device-onboarding-ec2"></a>

**設定 Amazon EC2 執行個體**

   登入 並使用 Amazon Linux AMI AWS 管理主控台 啟動 Amazon EC2 執行個體。 Amazon EC2 請參閱[《Amazon Elastic Container Registry 使用者指南》中的 Amazon EC2 入門](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html)。 *[https://docs.aws.amazon.com/AmazonECR/latest/userguide/](https://docs.aws.amazon.com/AmazonECR/latest/userguide/)*

1. <a name="managedintegrations-sdk-device-onboarding-buildenv"></a>

**設定建置環境**

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

   ```
   dnf install make gcc gcc-c++ cmake
   ```

1. <a name="managedintegrations-sdk-device-onboarding-network"></a>

**（選用） 設定網路**

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

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

   ```
   /* Provisioning the device PKCS11 with claim credential. */
   status = deviceCredentialProvisioning();
   ```

1. <a name="managedintegrations-sdk-device-onboarding-buildenv"></a>

**設定佈建參數**
**注意**  
遵循[佈建者](managedintegrations-sdk-device-provisionee.md)取得宣告憑證和私有金鑰，然後再繼續。

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


**佈建參數**  

<table>
<thead>
  <tr><th>巨集參數</th><th>說明</th><th>如何取得此資訊</th></tr>
</thead>
<tbody>
  <tr><td><code>IOTMI_ROOT_CA_PATH</code></td><td>根 CA 憑證檔案。</td><td>您可以從<i>AWS IoT Core 開發人員指南</i><a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-dc-prepare-device-test.html#iot-dc-prepare-device-test-step3">中的下載 Amazon 根 CA 憑證</a>區段下載此檔案。</td></tr>
  <tr><td><code>IOTMI_CLAIM_CERTIFICATE_PATH</code></td><td>宣告憑證檔案的路徑。</td><td rowspan="2">若要取得宣告憑證和私有金鑰，請使用 <a href="https://docs.aws.amazon.com/iot-mi/latest/APIReference/API_CreateProvisioningProfile.html">CreateProvisioningProfile</a> API 建立佈建設定檔。如需說明，請參閱<a href="managedintegrations-sdk-device-provisionee.md#sdk-provisionee-template-create">建立佈建設定檔</a>。</td></tr>
  <tr><td><code>IOTMI_CLAIM_PRIVATE_KEY_PATH</code></td><td>宣告私有金鑰檔案的路徑。</td></tr>
  <tr><td><code>IOTMI_MANAGEDINTEGRATIONS_ENDPOINT</code></td><td>受管整合的端點 URL。</td><td>若要取得受管整合端點，請使用 <a href="https://docs.aws.amazon.com/iot-mi/latest/APIReference/API_RegisterCustomEndpoint.html">RegisterCustomEndpoint</a> API。如需說明，請參閱<a href="managedintegrations-sdk-device-provisionee.md#sdk-provisionee-endpoint-create">註冊自訂端點</a>。</td></tr>
  <tr><td>IOTMI_MANAGEDINTEGRATIONS_ENDPOINT_PORT</td><td>Managed Integrations 端點的連接埠號碼</td><td>根據預設，連接埠 8883 用於 MQTT 發佈和訂閱操作。連接埠 443 已設定為裝置使用的應用程式層通訊協定交涉 (ALPN) TLS 延伸。</td></tr>
</tbody>
</table>


1. <a name="managedintegrations-sdk-device-onboarding-builddemo"></a>

**建置並執行示範應用程式**

   本節示範兩個 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。在執行[佈建者工作流程](managedintegrations-sdk-device-provisionee.md#managedintegrations-sdk-device-provisionee-how)之前完成 中提到的流程。

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

      ```
      [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]
      ```

   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_dm_air_purifier/iotmi_device_dm_air_purifier_demo
      ```

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


**空氣淨化器端點支援的叢集**  

<table>
<thead>
  <tr><th>Endpoint</th><th>叢集</th></tr>
</thead>
<tbody>
  <tr><td rowspan="4">端點 #1：空氣淨化器</td><td>OnOff</td></tr>
  <tr><td>風扇控制</td></tr>
  <tr><td>HEPA 篩選條件監控</td></tr>
  <tr><td>啟用的碳過濾器監控</td></tr>
  <tr><td rowspan="6">端點 #2：空氣品質感應器</td><td>空氣品質</td></tr>
  <tr><td>二氧化碳濃度測量</td></tr>
  <tr><td>Formaldehyde 集中度測量</td></tr>
  <tr><td>Pm25 集中度測量 </td></tr>
  <tr><td>Pm1 集中度測量</td></tr>
  <tr><td>揮發性有機化合物總集中度測量</td></tr>
</tbody>
</table>


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

1. <a name="managedintegrations-sdk-device-onboarding-next"></a>

**後續步驟：**

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

   1. <a name="managedintegrations-sdk-device-onboarding-hardwarecallback"></a>

**開發硬體回呼函數**

      實作硬體回呼函數之前，請先了解 API 的運作方式。此範例使用 On/Off OnOff 叢集和屬性來控制裝置函數。如需 API 詳細資訊，請參閱 [低階 C-Function APIs](managedintegrations-sdk-device-api.md)。

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

   1. <a name="managedintegrations-sdk-device-onboarding-endpoints"></a>

**設定端點和掛接硬體回呼函數**

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

      1. 建立裝置代理程式。

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

         1.  您的組態至少必須包含 **thingId** 和 **clientId** 參數。

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

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

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

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

         使用 建立端點`iotmiDev_Agent_addEndpoint()`，這需要：

         1. 唯一的端點 ID。

         1. 描述性端點名稱

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

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

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

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

   1. <a name="managedintegrations-sdk-device-onboarding-jobhandler"></a>

**使用任務處理常式來取得任務文件**

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

      1. 呼叫 `iotmi_JobsHandler_start` 以初始化任務處理常式。

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

      1. 成功取得任務文件時，請在 `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." ) );
         
         }
         ```