

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# End Device SDK の使用を開始する
<a name="managedintegrations-sdk-device-onboarding"></a>

Linux デバイスで End Device SDK を実行するには、次の手順に従います。このセクションでは、環境設定、ネットワーク設定、ハードウェア機能の実装、エンドポイント設定について説明します。

**重要**  
`examples` ディレクトリのデモンストレーションアプリケーションと のプラットフォーム抽象化レイヤー (PAL) 実装`platform/posix`は、参照のみを目的としています。実稼働環境では使用しないでください。

以下の手順の各ステップを注意深く確認し、マネージド統合とデバイスが適切に統合されていることを確認します。

**エンドデバイス SDK の統合**

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

**Amazon EC2 インスタンスのセットアップ**

   にサインイン AWS マネジメントコンソール し、Amazon Linux AMI を使用して Amazon EC2 インスタンスを起動します。Amazon *[Elastic Container Registry](https://docs.aws.amazon.com/AmazonECR/latest/userguide/)* [ユーザーガイドのAmazon EC2 の開始方法](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html)」を参照してください。

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 は、デバイスが使用する Application Layer Protocol Negotiation (ALPN) TLS 拡張機能用に設定されています。</td></tr>
</tbody>
</table>


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

**デモアプリケーションを構築して実行する**

   このセクションでは、CMake をビルドシステムとして使用する、シンプルなセキュリティカメラとエアピューリファイアの 2 つの Linux デモアプリケーションを示します。

   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 関数を実装します。実行[プロビジョンドワークフロー](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 関数を実装します。


**エアピュリファイアエンドポイントでサポートされているクラスター**  

<table>
<thead>
  <tr><th>Endpoint</th><th>クラスター</th></tr>
</thead>
<tbody>
  <tr><td rowspan="4">エンドポイント #1: Air Purifier</td><td>OnOff</td></tr>
  <tr><td>ファンコントロール</td></tr>
  <tr><td>HEPA フィルターのモニタリング</td></tr>
  <tr><td>アクティブ化されたカーボンフィルターのモニタリング</td></tr>
  <tr><td rowspan="6">エンドポイント #2: Air Quality Sensor</td><td>空気品質</td></tr>
  <tr><td>二酸化炭素濃度測定</td></tr>
  <tr><td>フォームの「濃度測定」</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>

**次のステップ:**

    Managed Integrations End device SDK およびデモアプリケーションが Amazon EC2 インスタンスで実行されました。これにより、独自の物理ハードウェアでアプリケーションを開発およびテストできます。この設定では、 Managed Integrations サービスを活用して AWS IoT デバイスを制御できます。

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

**ハードウェアコールバック関数の開発**

      ハードウェアコールバック関数を実装する前に、API の仕組みを理解してください。この例では、オン/オフクラスターと OnOff 属性を使用してデバイス関数を制御します。API の詳細については、「」を参照してください[低レベルの C 機能 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. エンドポイントを作成したら、適切なクラスター固有の登録関数を使用してクラスターを登録します。

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