nRF Connect SDK 和 Matter SDK 的 matter 协议版本
- nRF Connect SDK(NCS)是 Nordic 官方维护的,里面包含某个版本的 Matter SDK。
- Matter SDK 为 CSA 联盟维护的,里面包含各平台的SDK,其中包含了某个版本的 NCS。
需要探索最新标准 matter 协议,使用最新 Matter SDK ,去配置需要使用的 NCS 版本。
需要 Nordic 最新维护发布的稳定版本,直接使用 NCS 即可。
NCS 适配的 Matter 协议版本:
ZAP Tool
Matter开发主要包括两方面的工作:一是Matter应用本身的开发,二是非Matter应用开发。Matter应用开发本质上就是cluster/endpoint/node的添加、编辑、删除以及相关回调事件处理等,如前所述,这个需要通过 zcl 编辑工具 zap 来生成ember层的代码,以及手动添加或者修改其他c++文件来实现。
保证 zap 版本一致性:
NCS 安装:
~/ncs/v2.5.2/modules/lib/matter/scripts/setup/nrfconnect/get_zap.py -l ~/Nordic/Tools/zap_tool -o
Matter SDK 安装:
查看 ~/connectedhomeip/scripts/setup/zap.version,文件确认版本
到 https://github.com/project-chip/zap/releases,下载对应版本:
下载解压完成后,如:~/Nordic/Tools/zap_tool,将 zap_tool 文件夹添加到环境变量。
(已经安装了的旧版或者其他版本,Linux 系统下将 ~/.zap 这个文件夹删除,windows 下位于 C:\Users\${username}\.zap)
添加 Cluster
创建 Matter Template 工程
使用命令行打开 template.zap 文件,(windows 下路径默认用的是 '\',输入要换成 '/',否则出现乱码不兼容)
zap ~/template/src/template.zap --zcl ~/ncs/v2.5.2/modules/lib/matter/src/app/zap-templates/zcl/zcl.json --gen ~/ncs/v2.5.2/modules/lib/matter/src/app/zap-templates/app-templates.json
弹出ZCL窗口:
例子目前只有Endpoint 0,选择Endpoint 0,并选择“Enabled Clusters”,我们可以看到这个Endpoint使能了哪些cluster,比如 Descriptor cluster。
下面我们添加一个Endpoint以支持Matter On/Off Light设备,选择“ADD ENDPOINT”,如下添加:
完成添加后保存,点击 generate 生成代码到 template/src/zap-generated 文件夹中。或者使用python 脚本:
python ~/ncs/v2.5.0/modules/lib/matter/scripts/tools/zap/generate.py ~/template/src/template.zap -t src/app/zap-templates/app-templates.json -o ~/template/src/zap-generated
修改项目代码
添加 Matter stack 回调函数,以处理 controller 发送过来的命令,比如开灯。这个主要通过覆盖 MatterPostAttributeChangeCallback() 来实现更新 attribute 数值,以让 Matter stack 可以将最新的状态或者 event 同步给 controller。这个主要通过Clusters::OnOff::Attributes::OnOff::Set()之类的函数实现。
如 light_hulb 工程中的 zcl_callback.cpp:
/** Copyright (c) 2021 Nordic Semiconductor ASA** SPDX-License-Identifier: LicenseRef-Nordic-5-Clause*/#include <lib/support/logging/CHIPLogging.h>#include "app_task.h"#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/ConcreteAttributePath.h>using namespace ::chip;
using namespace ::chip::app::Clusters;
using namespace ::chip::app::Clusters::OnOff;void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath &attributePath, uint8_t type,uint16_t size, uint8_t *value)
{ClusterId clusterId = attributePath.mClusterId;AttributeId attributeId = attributePath.mAttributeId;if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) {ChipLogProgress(Zcl, "Cluster OnOff: attribute OnOff set to %" PRIu8 "", *value);AppTask::Instance().GetPWMDevice().InitiateAction(*value ? PWMDevice::ON_ACTION : PWMDevice::OFF_ACTION,static_cast<int32_t>(AppEventType::Lighting), value);} else if (clusterId == LevelControl::Id && attributeId == LevelControl::Attributes::CurrentLevel::Id) {ChipLogProgress(Zcl, "Cluster LevelControl: attribute CurrentLevel set to %" PRIu8 "", *value);if (AppTask::Instance().GetPWMDevice().IsTurnedOn()) {AppTask::Instance().GetPWMDevice().InitiateAction(PWMDevice::LEVEL_ACTION, static_cast<int32_t>(AppEventType::Lighting), value);} else {ChipLogDetail(Zcl, "LED is off. Try to use move-to-level-with-on-off instead of move-to-level");}}
}/** @brief OnOff Cluster Init** This function is called when a specific cluster is initialized. It gives the* application an opportunity to take care of cluster initialization procedures.* It is called exactly once for each endpoint where cluster is present.** @param endpoint Ver.: always** TODO Issue #3841* emberAfOnOffClusterInitCallback happens before the stack initialize the cluster* attributes to the default value.* The logic here expects something similar to the deprecated Plugins callback* emberAfPluginOnOffClusterServerPostInitCallback.**/
void emberAfOnOffClusterInitCallback(EndpointId endpoint)
{// Cluster 初始化后调用,在这里同步最初的 Cluster 状态// 在 InitCallback 之前,调用 Attributes 下的方法会返回失败。EmberAfStatus status;bool storedValue;/* Read storedValue on/off value */status = Attributes::OnOff::Get(endpoint, &storedValue);if (status == EMBER_ZCL_STATUS_SUCCESS) {/* Set actual state to the cluster state that was last persisted */AppTask::Instance().GetPWMDevice().InitiateAction(storedValue ? PWMDevice::ON_ACTION : PWMDevice::OFF_ACTION,static_cast<int32_t>(AppEventType::Lighting), reinterpret_cast<uint8_t *>(&storedValue));}AppTask::Instance().UpdateClusterState();
}