

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 与组件配置交互


组件配置 IPC 服务让您可以执行以下操作：
+ 获取和设置组件配置参数。
+ 订阅组件配置更新。
+ 在 Nucleus 应用组件配置更新之前对其进行验证。

**Topics**
+ [

## 最低 SDK 版本
](#ipc-component-configuration-sdk-versions)
+ [

## GetConfiguration
](#ipc-operation-getconfiguration)
+ [

## UpdateConfiguration
](#ipc-operation-updateconfiguration)
+ [

## SubscribeToConfigurationUpdate
](#ipc-operation-subscribetoconfigurationupdate)
+ [

## SubscribeToValidateConfigurationUpdates
](#ipc-operation-subscribetovalidateconfigurationupdates)
+ [

## SendConfigurationValidityReport
](#ipc-operation-sendconfigurationvalidityreport)

## 最低 SDK 版本


下表列出了与组件配置交互时 Amazon IoT Device SDK 必须使用的最低版本。


| SDK | 最低版本 | 
| --- | --- | 
|  [Amazon IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.2.10  | 
|  [Amazon IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.5.3  | 
|  [Amazon IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  | 
|  [Amazon IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

## GetConfiguration


获取核心设备上某个组件的配置值。您可以指定要获取配置值的键路径。

### 请求


此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  <a name="ipc-configuration-request-component-name"></a>
（可选）组件的名称。  
默认为发出请求的组件名称。

`keyPath`（Python：`key_path`）  
配置值的键路径。指定一个列表，其中每个条目都是配置对象中单个级别的键。例如，在以下配置中，指定 `["mqtt", "port"]` 以获取 `port` 的值。  

```
{
  "mqtt": {
    "port": 443
  }
}
```
要获取组件的完整配置，请指定一个空列表。

### 响应


此操作的响应包含以下信息：

`componentName`（Python：`component_name`）  <a name="ipc-configuration-response-component-name"></a>
组件名称。

`value`  
请求的配置，以对象形式表示。

### 示例


以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Rust ]

**Example 示例：获取配置**  

```
use core::mem::MaybeUninit;
use gg_sdk::{Sdk, UnpackedObject};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    // Get a configuration value at key path ["mqtt", "port"]
    let mut buf = [MaybeUninit::uninit(); 1024];

    let value = sdk
        .get_config(&["mqtt", "port"], None, &mut buf)
        .expect("Failed to get configuration");

    if let UnpackedObject::I64(port) = value.unpack() {
        println!("Configuration value: {port}");
    }
}
```

------
#### [ C ]

**Example 示例：获取配置**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    // Get a configuration value at key path ["mqtt", "port"]
    uint8_t response_mem[1024];
    GgObject value;

    err = ggipc_get_config(
        GG_BUF_LIST(GG_STR("mqtt"), GG_STR("port")),
        NULL, // component_name (NULL = current component)
        GG_BUF(response_mem),
        &value
    );
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to get configuration.\n");
        exit(-1);
    }

    if (gg_obj_type(value) == GG_TYPE_I64) {
        printf("Configuration value: %" PRId64 "\n", gg_obj_into_i64(value));
    } else if (gg_obj_type(value) == GG_TYPE_BUF) {
        GgBuffer buf = gg_obj_into_buf(value);
        printf("Configuration value: %.*s\n", (int) buf.len, buf.data);
    } else {
        printf("Configuration value is of unexpected type.\n");
    }
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：获取配置**  

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    // Get a configuration value at key path ["mqtt", "port"]
    std::array key_path = { gg::Buffer { "mqtt" }, gg::Buffer { "port" } };
    int64_t value = 0;

    error = client.get_config(key_path, std::nullopt, value);
    if (error) {
        std::cerr << "Failed to get configuration.\n";
        exit(-1);
    }

    std::cout << "Configuration value: " << value << "\n";
}
```

------

## UpdateConfiguration


更新核心设备上此组件的配置值。

### 请求


此操作的请求包含以下参数：

`keyPath`（Python：`key_path`）  
（可选）要更新的容器节点（对象）的键路径。指定一个列表，其中每个条目都是配置对象中单个级别的键。例如，在以下配置中指定键路径 `["mqtt"]` 和合并值 `{ "port": 443 }` 以设置 `port` 的值。  

```
{
  "mqtt": {
    "port": 443
  }
}
```
键路径必须在配置中指定容器节点（对象）。如果组件配置中不存在该节点，则此操作会创建该节点并将其值设置为 `valueToMerge` 中的对象。  
默认为配置对象的根目录。

`timestamp`  
当前 Unix 纪元时间（以毫秒为单位）。此操作使用此时间戳来解析键的并发更新。如果组件配置中的键的时间戳大于请求中的时间戳，则请求将失败。

`valueToMerge`（Python：`value_to_merge`）  
要在 `keyPath` 中指定的位置合并的配置对象。有关更多信息，请参阅 [更新组件配置](update-component-configurations.md)。

### 响应


此操作在其响应中未提供任何信息。

### 示例


以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Rust ]

**Example 示例：更新配置**  

```
use gg_sdk::Sdk;

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    // Update configuration value at key path ["mqtt", "port"] to 443
    sdk.update_config(&["mqtt", "port"], None, 443)
        .expect("Failed to update configuration");

    println!("Successfully updated configuration.");
}
```

------
#### [ C ]

**Example 示例：更新配置**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    // Update configuration value at key path ["mqtt", "port"] to 443
    err = ggipc_update_config(
        GG_BUF_LIST(GG_STR("mqtt"), GG_STR("port")),
        NULL, // timestamp (NULL = current time)
        gg_obj_i64(443)
    );
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to update configuration.\n");
        exit(-1);
    }

    printf("Successfully updated configuration.\n");
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：更新配置**  

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    // Update configuration value at key path ["mqtt", "port"] to 443
    std::array key_path = { gg::Buffer { "mqtt" }, gg::Buffer { "port" } };

    error = client.update_config(key_path, 443);
    if (error) {
        std::cerr << "Failed to update configuration.\n";
        exit(-1);
    }

    std::cout << "Successfully updated configuration.\n";
}
```

------

## SubscribeToConfigurationUpdate


订阅即可在组件配置更新时接收通知。订阅某个键后，只要该键的任何子项有所更新，您都会收到通知。

<a name="ipc-subscribe-operation-note"></a>此操作是一种订阅操作，您可以在其中订阅事件消息流。要使用此操作，请定义一个流响应处理程序，其中包含处理事件消息、错误和流关闭的函数。有关更多信息，请参阅 [订阅 IPC 事件流](interprocess-communication.md#ipc-subscribe-operations)。

**事件消息类型：**`ConfigurationUpdateEvents`

### 请求


此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  <a name="ipc-configuration-request-component-name"></a>
（可选）组件的名称。  
默认为发出请求的组件名称。

`keyPath`（Python：`key_path`）  
要订阅的配置值的键路径。指定一个列表，其中每个条目都是配置对象中单个级别的键。例如，在以下配置中，指定 `["mqtt", "port"]` 以获取 `port` 的值。  

```
{
  "mqtt": {
    "port": 443
  }
}
```
要订阅组件配置中所有值的更新，请指定一个空列表。

### 响应


此操作的响应包含以下信息：

`messages`  
通知消息流。此对象 `ConfigurationUpdateEvents` 包含以下信息：    
`configurationUpdateEvent`（Python：`configuration_update_event`）  
配置更新事件。此对象 `ConfigurationUpdateEvent` 包含以下信息：    
`componentName`（Python：`component_name`）  <a name="ipc-configuration-response-component-name"></a>
组件名称。  
`keyPath`（Python：`key_path`）  
已更新的配置值的键路径。

### 示例


以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Rust ]

**Example 示例：订阅配置更新**  

```
use gg_sdk::Sdk;
use std::{thread, time::Duration};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    // Subscribe to configuration updates for key path ["mqtt"]
    let callback = |component_name: &str, key_path: &[&str]| {
        println!(
            "Received configuration update for component: {component_name}"
        );
        println!("Key path: {key_path:?}");
    };

    let _sub = sdk
        .subscribe_to_configuration_update(None, &["mqtt"], &callback)
        .expect("Failed to subscribe to configuration updates");

    println!("Successfully subscribed to configuration updates.");

    // Keep the main thread alive, or the process will exit.
    loop {
        thread::sleep(Duration::from_secs(10));
    }
}
```

------
#### [ C ]

**Example 示例：订阅配置更新**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

static void on_subscription_response(
    void *ctx,
    GgBuffer component_name,
    GgList key_path,
    GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) handle;

    printf(
        "Received configuration update for component: %.*s\n",
        (int) component_name.len,
        component_name.data
    );

    printf("Key path: [");
    for (size_t i = 0; i < key_path.len; i++) {
        if (i > 0) {
            printf(", ");
        }
        GgObject *obj = &key_path.items[i];
        if (gg_obj_type(*obj) == GG_TYPE_BUF) {
            GgBuffer key = gg_obj_into_buf(*obj);
            printf("\"%.*s\"", (int) key.len, key.data);
        }
    }
    printf("]\n");
}

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    // Subscribe to configuration updates for key path ["mqtt"]
    GgIpcSubscriptionHandle handle;
    err = ggipc_subscribe_to_configuration_update(
        NULL, // component_name (NULL = current component)
        GG_BUF_LIST(GG_STR("mqtt")),
        on_subscription_response,
        NULL,
        &handle
    );
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to subscribe to configuration updates.\n");
        exit(-1);
    }

    printf("Successfully subscribed to configuration updates.\n");

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }

    // To stop subscribing, close the stream.
    ggipc_close_subscription(handle);
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：订阅配置更新**  

```
#include <gg/ipc/client.hpp>
#include <unistd.h>
#include <iostream>

class ResponseHandler : public gg::ipc::ConfigurationUpdateCallback {
    void operator()(
        std::string_view component_name,
        gg::List key_path,
        gg::ipc::Subscription &handle
    ) override {
        (void) handle;
        std::cout << "Received configuration update for component: "
                  << component_name << "\n";
        std::cout << "Key path: [";
        for (size_t i = 0; i < key_path.size(); i++) {
            if (i > 0) {
                std::cout << ", ";
            }
            std::cout << "\"" << get<gg::Buffer>(key_path[i]) << "\"";
        }
        std::cout << "]\n";
    }
};

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    // Subscribe to configuration updates for key path ["mqtt"]
    std::array key_path = { gg::Buffer { "mqtt" } };

    static ResponseHandler handler;
    error = client.subscribe_to_configuration_update(
        key_path, std::nullopt, handler
    );
    if (error) {
        std::cerr << "Failed to subscribe to configuration updates.\n";
        exit(-1);
    }

    std::cout << "Successfully subscribed to configuration updates.\n";

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }
}
```

------

## SubscribeToValidateConfigurationUpdates


订阅即可在此组件配置更新之前接收通知。这样，组件就可以验证自己配置的更新。使用 [SendConfigurationValidityReport](#ipc-operation-sendconfigurationvalidityreport) 操作告知 Nucleus 配置是否有效。

**重要**  
本地部署不会通知组件更新。

<a name="ipc-subscribe-operation-note"></a>此操作是一种订阅操作，您可以在其中订阅事件消息流。要使用此操作，请定义一个流响应处理程序，其中包含处理事件消息、错误和流关闭的函数。有关更多信息，请参阅 [订阅 IPC 事件流](interprocess-communication.md#ipc-subscribe-operations)。

**事件消息类型：**`ValidateConfigurationUpdateEvents`

### 请求


此操作的请求没有任何参数。

### 响应


此操作的响应包含以下信息：

`messages`  
通知消息流。此对象 `ValidateConfigurationUpdateEvents` 包含以下信息：    
`validateConfigurationUpdateEvent`（Python：`validate_configuration_update_event`）  
配置更新事件。此对象 `ValidateConfigurationUpdateEvent` 包含以下信息：    
`deploymentId`（Python：`deployment_id`）  
更新组件的 Amazon IoT Greengrass 部署的 ID。  
`configuration`  
包含新配置的对象。

## SendConfigurationValidityReport


告知 Nucleus 对此组件的配置更新是否有效。如果您告知 Nucleus 新配置无效，则部署将失败。使用 [SubscribeToValidateConfigurationUpdates](#ipc-operation-subscribetovalidateconfigurationupdates) 操作订阅即可验证配置更新。

如果组件未响应验证配置更新通知，则 Nucleus 会按您在部署配置验证策略中指定的时间等待。超时之后，Nucleus 继续部署。默认组件验证超时值为 20 秒。有关更多信息，请参阅[创建部署](create-deployments.md)以及您在调用[CreateDeployment](https://docs.amazonaws.cn/greengrass/v2/APIReference/API_CreateDeployment.html)操作时可以提供的[DeploymentConfigurationValidationPolicy](https://docs.amazonaws.cn/greengrass/v2/APIReference/API_DeploymentConfigurationValidationPolicy.html)对象。

### 请求


此操作的请求包含以下参数：

`configurationValidityReport`（Python：`configuration_validity_report`）  
告知 Nucleus 配置更新是否有效的报告。此对象 `ConfigurationValidityReport` 包含以下信息：    
`status`  
有效状态。此枚举 `ConfigurationValidityStatus` 包含以下值：  
+ `ACCEPTED` – 配置有效，Nucleus 可以将其应用于该组件。
+ `REJECTED` – 配置无效，部署失败。  
`deploymentId`（Python：`deployment_id`）  
请求配置更新的 Amazon IoT Greengrass 部署的 ID。  
`message`  
（可选）用于报告配置无效原因的消息。

### 响应


此操作在其响应中未提供任何信息。