ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Matter connectedhomeip 实战:ESP32 Persistent Storage 示例 —— 基于 NVS 的 Key Value Store 测试与 API 使用指南

Matter connectedhomeip 实战:ESP32 Persistent Storage 示例 —— 基于 NVS 的 Key Value Store 测试与 API 使用指南 Matter connectedhomeip 实战ESP32 Persistent Storage 示例 —— 基于 NVS 的 Key Value Store 测试与 API 使用指南【免费下载链接】connectedhomeipMatter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumers, guided by the Connectivity Standards Alliance.项目地址: https://gitcode.com/GitHub_Trending/co/connectedhomeip本指南围绕 connectedhomeipMatter/Project CHIP仓库中的persistent-storageESP32 示例展开完整介绍该示例的设计目标、入口代码、KeyValueStoreManager公共 API 与平台实现、8 个 KVS 测试用例的含义以及从环境准备、构建、烧录到串口监控的全流程操作。读者完成阅读后将能够在自己的 ESP32 Matter 应用中正确调用持久化键值存储接口并理解 NVS 底层实现的能力边界与当前限制。示例概览与设计目标示例 README 明确指出这是一个用于测试和演示 key value storageKVSAPI 的示例程序。它的价值体现在两个层面平台验证当 KVS 实现在不同平台上适配bring-up时用这套统一测试用例检验各平台实现的正确性API 教学为开发者提供一个如何调用KeyValueStoreMgr()接口读写持久化数据的完整参考实现。README 同时说明了一个重要的演进方向未来当所有平台都具备可用的 KVS 后这个示例可以被迁移为单元测试unit test从示例工程演变为平台回归测试。注意该文档还明确标注了当前平台的已知限制——ESP32 平台的 KVS 尚未完全实现特别是不支持 offset 读取与 partial部分读取。这一限制与源码实现完全吻合后文会从实现层面详细解释。环境准备与前置文档示例 README 指引读者先完成两件事对应的完整操作分别位于ESP-IDF 与 CHIP/Matter 环境搭建构建与配对commissioning指南其中构建指南docs/platforms/esp32/build_app_and_commission.md给出了完整的环境变量配置流程这是所有 ESP32 示例包括本示例共用的基础步骤# 1) 激活 ESP-IDF 工具链 $ cd path/to/esp-idf $ source export.sh # 2) 激活 Matter 环境需在 export.sh 之后执行 $ cd path/to/connectedhomeip $ source scripts/activate.sh # 3) 可选启用 Ccache 加速 IDF 构建 $ export IDF_CCACHE_ENABLE1示例代码结构与入口分析persistent-storage目录在仓库中是一个跨平台共享示例ESP32 只是其中一个平台实现。整体结构如下examples/persistent-storage/KeyValueStorageTest.h —— 跨平台共享的测试声明定义RunKvsTest()入口和TestConfigurations枚举examples/persistent-storage/KeyValueStorageTest.cpp —— 跨平台共享的测试实现共 7 个测试函数examples/persistent-storage/esp32/main/main.cpp —— ESP32 平台入口app_main()examples/persistent-storage/esp32/CMakeLists.txt 与 main/CMakeLists.txt —— ESP-IDF 构建配置examples/persistent-storage/esp32/sdkconfig.defaults 与 partitions.csv —— 工程默认配置与分区表。app_main 入口初始化 NVS 后循环跑测试ESP32 入口代码main.cpp的逻辑非常清晰extern C void app_main() { esp_err_t err nvs_flash_init(); if (err ! ESP_OK) { ESP_LOGE(TAG, nvs_flash_init() failed: %s, esp_err_to_name(err)); return; } ESP_LOGI(TAG, ); ESP_LOGI(TAG, chip-esp32-persitent-storage-example starting); ESP_LOGI(TAG, ); // Run tests while (true) { ESP_LOGI(TAG, Running Tests:); // Partial and offset reads are not currently supported on the ESP32 // platform, skip these tests, chip::RunKvsTest(chip::SKIP_MULTI_READ_TEST); vTaskDelay(60000); // Run every minute } }关键点必须先nvs_flash_init()ESP32 的 KVS 底层基于 ESP-IDF 的 NVSNon-Volatile Storage子系统使用前必须初始化 flash 上的 NVS 分区。初始化失败直接退出不做任何后续操作以SKIP_MULTI_READ_TEST参数运行测试这与 README 所述的平台限制一一对应——ESP32 尚不支持 offset/partial 读取因此跳过了专门验证多段读取的TestMultiRead用例测试每 60 秒循环执行一次vTaskDelay(60000)让设备可以反复对同一片 flash 进行写入/读取/擦除压力测试便于观察 NVS 的磨损与稳定性表现。共享测试的入口与配置枚举KeyValueStorageTest.h 定义了测试配置枚举enum TestConfigurations { RUN_ALL_TESTS, // 运行全部 7 个测试含 TestMultiRead SKIP_MULTI_READ_TEST // 跳过多段读取测试ESP32 当前使用 }; void RunKvsTest(TestConfigurations test_config RUN_ALL_TESTS);支持多段读取的平台可以传入RUN_ALL_TESTS运行全部用例不支持的平台如当前的 ESP32则传入SKIP_MULTI_READ_TEST。KeyValueStoreManager统一的 KVS 公共 API所有平台共享的公共 API 定义在 src/include/platform/KeyValueStoreManager.h 中位于命名空间chip::DeviceLayer::PersistedStorage。应用侧通过单例访问接口KeyValueStoreMgr()获取平台实现。三个核心操作API说明关键返回码Put(key, value, value_size)写入键值对key 已存在则覆盖CHIP_NO_ERRORCHIP_ERROR_INVALID_ARGUMENTkey 为空/过长或 value 过大CHIP_ERROR_PERSISTED_STORAGE_FAILEDGet(key, buffer, buffer_size, read_bytes_size, offset_bytes)读取键对应的值到缓冲区可指定起始偏移CHIP_ERROR_BUFFER_TOO_SMALL缓冲区放不下全部数据时返回并返回已拷贝字节数CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUNDkey 不存在CHIP_ERROR_INTEGRITY_CHECK_FAILED数据损坏Delete(key)删除键值对CHIP_NO_ERRORCHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUNDGet的一个特别用法是探测 key 是否存在传入nullptr缓冲区与0大小此时返回CHIP_NO_ERROR或CHIP_ERROR_BUFFER_TOO_SMALL都说明 key 存在详见测试用例TestKeyExistence。模板重载对任意平凡可拷贝类型透明读写除了原始指针版本KeyValueStoreManager还提供了基于模板的重载KeyValueStoreManager.h让uint32_t、数组、结构体等**平凡可拷贝类型trivially copyable**可以直接读写template typename T CHIP_ERROR Get(const char * key, T * value) { static_assert(std::is_trivially_copyableT(), KVS values must copyable); static_assert(!std::is_pointerT(), KVS values cannot be pointers); static_assert(CHAR_BIT 8, Current implementation assumes 8 bit.); return Get(key, value, sizeof(T)); } template typename T CHIP_ERROR Put(const char * key, const T value) { static_assert(std::is_trivially_copyableT(), KVS values must copyable); static_assert(!std::is_pointerT(), KVS values cannot be pointers); static_assert(CHAR_BIT 8, Current implementation assumes 8 bit.); return Put(key, value, sizeof(T)); }三个static_assert约束了类型边界必须平凡可拷贝、不能是指针、假定字节宽度为 8 位。对象大小由编译器从类型自动推导调用方无需手工指定。平台实现的分发机制公共类通过静态分发把调用转发给平台实现KeyValueStoreManager.hinline CHIP_ERROR KeyValueStoreManager::Put(const char * key, const void * value, size_t value_size) { return static_castImplClass *(this)-_Put(key, value, value_size); }平台实现类KeyValueStoreManagerImpl以friend class KeyValueStoreManager的方式声明提供_Put/_Get/_Delete前缀方法。ImplClass由CHIP_DEVICE_LAYER_TARGET宏决定构建时通过KeyValueStoreManagerImpl.h按目标平台引入对应实现。这正是本示例能在 Linux、QPG、Infineon PSOC6、ESP32 等多个平台复用的架构基础。七大 KVS 测试用例逐项解析KeyValueStorageTest.cpp 中共定义了 7 个测试函数RunKvsTest()逐个执行并通过RUN_TEST宏打印PASSED/FAILED失败时附带FormatCHIPError格式化的错误信息。每个用例的模式都是写入 → 读取 → 校验 → 删除因此可以反复运行而不污染存储。测试函数测试的 key验证内容TestEmptyString()str_key写入空字符串长度为 0 的值后再读回校验读回内容与长度覆盖空值边界TestKeyExistence()str_key用Get(key, nullptr, 0)探测 key 是否存在允许返回CHIP_NO_ERROR或CHIP_ERROR_BUFFER_TOO_SMALLTestString()str_key字符串test_value的完整写入/读回/删除往返TestUint32()uint32_key通过模板重载读写单个uint32_t数值TestArray()array_key通过模板重载读写uint32_t[5]数组用memcmp逐字节比对TestStruct()struct_key自定义结构体{uint8_t value1; uint32_t value2;}的序列化读写逐字段校验TestUpdateValue()update_key连续 10 次更新同一个 key值 0~9每次写后立即读回校验验证覆盖更新语义TestMultiRead()multi_key以i * sizeof(uint32_t)为 offset 分 5 次读取数组元素验证偏移读取前 4 次应返回CHIP_ERROR_BUFFER_TOO_SMALL最后一次返回CHIP_NO_ERROR其中TestMultiRead()是唯一被 ESP32 跳过的用例KeyValueStorageTest.cpp其注释与实现都依赖offset_bytes参数——而该参数正是 ESP32 当前未实现的能力。ESP32 平台实现NVS 之上的 KVS 适配层ESP32 的实现位于 src/platform/ESP32/KeyValueStoreManagerImpl.cpp 与 KeyValueStoreManagerImpl.h它把 Matter 的KeyValueStoreManager抽象直接映射到 ESP-IDF 的 NVS API 之上。命名空间与单例实现类持有静态单例sInstance并使用固定的 NVS 命名空间class KeyValueStoreManagerImpl final : public KeyValueStoreManager { private: static inline const char kNamespace[] CHIP_KVS; static KeyValueStoreManagerImpl sInstance; };即所有 Matter KVS 数据都存放在 NVS 命名空间CHIP_KVS下。同时提供两个访问函数KeyValueStoreManagerImpl.hKeyValueStoreMgr()—— 返回公共接口单例应用通用代码使用KeyValueStoreMgrImpl()—— 返回平台专属接口单例需要访问 ESP32 特有能力时使用。写/读/删与 NVS API 的对应关系Matter 方法底层 NVS 调用说明_Putnvs_set_blob()nvs_commit()以 blob 形式写入原始字节nvs_commit确保落盘持久化_Getnvs_get_blob()读取 blobvalue可为nullptr以探测 key 是否存在_Deletenvs_erase_key()nvs_commit()擦除指定 keyEraseAllnvs_erase_all()nvs_commit()清空CHIP_KVS命名空间下全部数据所有 NVS 句柄通过 RAII 类Internal::ScopedNvsHandle管理见 src/platform/ESP32/ScopedNvsHandle.h以只读NVS_READONLY或读写NVS_READWRITE模式打开作用域退出自动释放。错误码通过ReturnMappedErrorOnFailure从esp_err_t映射为CHIP_ERROR。长 key 的 SHA1 哈希处理实现中最具工程细节的部分是HashIfLongKey()KeyValueStoreManagerImpl.cpp。ESP-IDF NVS 对 key 名称长度有硬性上限NVS_KEY_NAME_MAX_SIZE即 15 字符而 Matter 的 KVS 抽象并不限制 key 长度。为解决该矛盾当 key 长度 ≥ 15 时对 key 做SHA1 哈希取前 7.5 字节转换为十六进制字符串作为实际 NVS key哈希结果只包含十六进制字符0-9a-f而正常的 Matter KVS key 前缀通常包含/因此哈希生成的 key 不会与普通 key 冲突函数通过返回值区分是否发生了哈希true表示已哈希调用方随后用哈希结果替换原始 key。代码注释中明确记录了设计权衡虽然 SHA1 取 8 字节存在理论上的冲突概率但在实际使用场景中可能性很低。偏移读取明确的未实现边界_Get的第一行就给出了 README 所述限制的代码级证据KeyValueStoreManagerImpl.cpp// Offset and partial reads are not supported in nvs, for now just return NOT_IMPLEMENTED. Support can be added in the // future if this is needed. VerifyOrReturnError(offset_bytes 0, CHIP_ERROR_NOT_IMPLEMENTED);任何offset_bytes ! 0的读取都会直接返回CHIP_ERROR_NOT_IMPLEMENTED。头文件同样在注释中说明Currently this platform does not support partial and offset reads, these will returnCHIP_ERROR_NOT_IMPLEMENTED。这就是示例入口必须传SKIP_MULTI_READ_TEST的根本原因。工程构建配置解析顶层 CMakeListsexamples/persistent-storage/esp32/CMakeLists.txtcmake_minimum_required(VERSION 3.20) set(PROJECT_VER v1.0) set(PROJECT_VER_NUMBER 1) include($ENV{IDF_PATH}/tools/cmake/project.cmake) include(${CMAKE_CURRENT_LIST_DIR}/third_party/connectedhomeip/examples/common/cmake/idf_flashing.cmake) set(EXTRA_COMPONENT_DIRS ${CMAKE_CURRENT_LIST_DIR}/third_party/connectedhomeip/config/esp32/components ) project(chip-persistent-storage) idf_build_set_property(CXX_COMPILE_OPTIONS -stdgnu17;-Os;-DCHIP_HAVE_CONFIG_H APPEND) idf_build_set_property(C_COMPILE_OPTIONS -Os APPEND) # For the C3, project_include.cmake sets -Wno-format, but does not clear various # flags that depend on -Wformat idf_build_set_property(COMPILE_OPTIONS -Wno-format-nonliteral;-Wno-format-security APPEND) # -Wmaybe-uninitialized has too many false positives, including on std::optional # and chip::Optional. Make it nonfatal. idf_build_set_property(COMPILE_OPTIONS -Wno-errormaybe-uninitialized APPEND) flashing_script()要点工程名chip-persistent-storage要求CMake ≥ 3.20C 编译采用-stdgnu17与-Os尺寸优化适合 flash 受限的嵌入式环境并定义-DCHIP_HAVE_CONFIG_H通过EXTRA_COMPONENT_DIRS引入 connectedhomeip 的 ESP32 公共组件config/esp32/components这是所有 ESP32 示例复用 SDK 代码的通用手法-Wno-errormaybe-uninitialized用于规避 GCC 对std::optional/chip::Optional的误报源码注释引用了 gcc.gnu.org bug 80635flashing_script()会生成chip-persistent-storage.flash.py烧录脚本供后续一键烧录。main 组件examples/persistent-storage/esp32/main/CMakeLists.txtmain 组件把跨平台共享的persistent-storage目录含KeyValueStorageTest.cpp一并纳入编译idf_component_register(PRIV_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/persistent-storage SRC_DIRS ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/persistent-storage) target_compile_options(${COMPONENT_LIB} PRIVATE -DCHIP_HAVE_CONFIG_H)注意此处引用的third_party/connectedhomeip是该示例目录内部的 vendored SDK 副本examples/persistent-storage/esp32/third_party/connectedhomeip它保持了 SDK 的标准目录布局。sdkconfig 默认配置examples/persistent-storage/esp32/sdkconfig.defaults# Use a custom partition table CONFIG_PARTITION_TABLE_CUSTOMy CONFIG_PARTITION_TABLE_FILENAMEpartitions.csv # Vendor and product id CONFIG_DEVICE_VENDOR_ID0xFFF1 CONFIG_DEVICE_PRODUCT_ID0x8009 # Enable HKDF in mbedtls CONFIG_MBEDTLS_HKDF_Cy使用自定义分区表见下方partitions.csv预设厂商 ID0xFFF1与产品 ID0x8009开发用途的测试 VID/PID启用 mbedtls 的 HKDF 支持Matter 加密密钥派生所需。分区表examples/persistent-storage/esp32/partitions.csv# Name, Type, SubType, Offset, Size, Flags # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0xC000, phy_init, data, phy, , 0x1000, # Factory partition size about 1.9MB factory, app, factory, , 1920K,三个分区各司其职nvs分区48 KB存放键值数据Matter KVS 的CHIP_KVS命名空间就落在这里phy_init存放 WiFi/蓝牙射频校准数据factory为应用固件分区约 1.9 MB。由于 KVS 测试会持续写入 NVS该分区大小直接影响可容纳的键值条目数与擦写寿命。构建、烧录与运行根据 docs/platforms/esp32/build_app_and_commission.md 的标准流程本示例的构建运行步骤如下1. 进入示例目录并设定目标芯片$ cd examples/persistent-storage/esp32 $ idf.py set-target esp32 # 或 esp32c3 / esp32s3 等目标该文档指出所有 Matter demo 应用支持 ESP32、ESP32C3、ESP32S3 芯片变体ESP32H2/ESP32C6 目前仅针对 lighting-app、lit-icd-app、all-clusters-app 验证过本示例请以仓库实际支持为准。2. 构建默认使用sdkconfig.defaults直接执行$ idf.py build如需自定义配置可先运行idf.py menuconfig调整或通过idf.py -D SDKCONFIG_DEFAULTS... build指定其他 defaults 文件。3. 烧录与监控$ idf.py -p (PORT) erase_flash $ idf.py -p (PORT) flash monitor将(PORT)替换为实际串口设备名Linux 下通常是/dev/ttyUSB0。首次烧录前建议erase_flash清空整片 flash避免残留数据干扰测试。监控模式下按Ctrl]退出。4. 查看测试输出启动后串口会周期性打印 chip-esp32-persitent-storage-example starting Running Tests: KeyValueStoreMgr().Put(...): PASSED ...每 60 秒循环一轮全部用例除被跳过的TestMultiRead输出PASSED即说明 ESP32 平台的 KVS 基础读写/更新/删除能力正常。5. 使用生成脚本烧录可选构建过程中flashing_script()已生成chip-persistent-storage.flash.py可一键烧录$ export ESPPORT/dev/tty.SLAB_USBtoUART $ idf.py build $ idf.py flashing_script $ python chip-persistent-storage.flash.py当前限制与后续演进综合 README 与源码当前版本的要点总结如下offset / partial 读取未实现KeyValueStoreManagerImpl::_Get对非零偏移直接返回CHIP_ERROR_NOT_IMPLEMENTED示例因此以SKIP_MULTI_READ_TEST跳过TestMultiReadkey 长度限制的适配NVS key 最长 15 字符Matter 层通过 SHA1 哈希 十六进制截断来支持长 key持久化语义写入与删除均显式调用nvs_commit保证数据真正落盘演进方向README 明确该示例未来在平台条件成熟后可转为单元测试成为 CI 中校验各平台 KVS 实现一致性的回归用例。对于需要在 ESP32 上使用持久化存储的 Matter 开发者可以直接借鉴本示例的调用模式nvs_flash_init()初始化 →KeyValueStoreMgr().Put/Get/Delete读写 → 通过返回码判断结果同时在设计业务时避开对偏移读取的依赖或关注 SDK 后续版本对该能力的支持。延伸阅读KeyValueStoreManager 公共 API 头文件ESP32 KVS 平台实现跨平台共享测试用例ESP32 平台配置选项总览ESP32 构建与配对完整指南【免费下载链接】connectedhomeipMatter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumers, guided by the Connectivity Standards Alliance.项目地址: https://gitcode.com/GitHub_Trending/co/connectedhomeip创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表