Matter开发,看这一篇就够了

############ 本文更新于2025年2月18日,对齐Matter1.4和nRF Connect SDK v2.9.0 ############

1. Matter介绍

Matter(以前称为 Project Connected Home over IP 或 Project CHIP)是由CSA联盟制定的一个应用层面的标准,旨在打造一个统一的智能家居应用标准,以消除智能家居市场的碎片化。在Matter出来之前,智能家居市场是比较混乱的,每一个生态都有自己的协议,比如苹果有自己的 Homekit,Google有自己的Weave,亚马逊有自己的Echo,ZigBee联盟有自己的Zigbee,这种割裂让设备商很头疼,他们需要为不同的生态制造不同的设备,最终用户也很头疼,他们需要学习各种生态的智能家居设备的使用方式。为此CSA提出了Matter技术,以打造一个统一的标准,让一个设备可以在各个生态中工作,并给最终用户呈现统一的使用界面。

需要说明的是,Matter只是一个应用标准,它的传输是建立在支持IPv6的TCP和UDP协议上的,Matter不对传输层进行约定,Matter也不对网络进行约定,但是Matter约定了只能使用Thread/Wi-Fi/Ethernet三种连接协议。Thread协议由Thread Group制定,所以Matter over Thread产品必须通过Thread Group的认证。Wi-Fi则由Wi-Fi联盟进行规范,所以Matter over Wi-Fi产品必须通过Wi-Fi Alliance认证。为了让Matter产品加入Matter网络,需要一个配网的过程,Matter支持三种类型的配网方式,而低功耗蓝牙则是首选配网方式,所以Matter产品一般都会要求支持低功耗蓝牙功能。

Matter技术包含了三份规格书及其他要求文档,大家可以从以下链接获取Matter技术规范:

https://csa-iot.org/developer-resource/specifications-download-request/ 

 其中Core specification是它的核心规范,Application cluster specification对Matter组件cluster进行了详细规定,Device library specification则是对设备层面的一些约束和规定。

不像蓝牙和Wi-Fi,即使你不过认证,也照样可以使用蓝牙和Wi-Fi技术。由于Matter采用了PKI技术,而且它又是一个应用规范,你要使用Matter技术,必须通过Matter认证。为此CSA提供了多种资源帮助大家学习了解Matter,大家可以参考如下资源网站:

https://groups.csa-iot.org/wg/all-users/home/matter-resource-kit

 

Matter是一个非常复杂而又现代的标准,但是短短4年时间,Matter就实现了从提出到落地到追捧的成绩,不得不说这是一个“Matter奇迹”。下面我们一起来了解一下这个“奇迹”的更多细节。

1.1  Matter架构

如下展示了Matter协议栈在整个系统中的位置,可以看出Matter就是一个应用协议。

 

Matter协议栈本身又是由application, data model, interaction model, action framing, security, Message Framing and Routing和Transport and IP Framing组成,如下:

 

Application

Application层定义最终产品的业务逻辑。例如,对于门锁应用程序,业务逻辑可以根据来自特定语音命令来打开和关闭门锁。它还可以定义用PIN码开锁或者LED反应等。

Data Model

Data Model层用来描述Matter节点支持的远程操作,这里面主要运用了attributes, commands和events三个Matter概念,我们把相应的attributes,commands和events组合,就成了Matter设备里面的一个基石:cluster。Cluster本身是一个抽象的概念,用来定义一个一个的Matter设备,具体定义可参见之前的:Matter Application Cluster Specification。正因为有了cluster,才能让用户快速开发出自己的Matter产品,同时保证互联互通。 

Interaction Model

Data Model层对数据进行了抽象,而Interaction Model层则用来定义节点与节点之间如何交换数据。通俗地讲,Interaction model就是用来规定交互命令集的,我们把发起交互的节点叫initiator (一般都是client设备),而接收者称为target (一般为server设备)。

Action Framing

Action Framing层用来把Interaction Model层的命令转成serialized格式。

Security

Security层把上面的数据进行加密并添加MAC。

Message Framing and Routing

这层主要把包头添加到数据中,组成一个真正的包。

Transport and IP Framing

这层把数据传输到对端,主要是利用TCP或者UDP协议,同时Matter定义了Message Reliability Protocol (MRP)协议,用来信息确认,重传和拒绝重复信息。如前所述,在配网(commissioning)过程中,通信是建立在Bluetooth Transport Protocol (BTP)协议之上。

1.2 Matter拓扑结构

Matter可以同时支持Wi-Fi/Thread/Ethernet,也就是说Matter可以让不同网络中的设备进行互联互通通信,这个主要是指Thread board router 可以实现Wi-Fi和Thread通信互转。不仅如此,Matter还允许接入其他网络设备,比如ZigBee设备,这主要通过一个Matter bridge设备来实现。在Matter拓扑结构中,还有一个节点非常重要:Matter controller,Matter controller用来完成配网和远程控制设备,比如苹果的HomePod mini和Home app就是一个典型的Matter controller节点。如下为一个典型的Matter拓扑结构:

 

一般来说,一个Matter网络称为一个Fabric,共享同一个根操作证书的所有节点可以归为同一个Fabric,简单来说,一个生态就是一个Fabric(当然也可以包含多个),比如家里同时有苹果Google亚马逊的音箱,那么你可以认为你家里有三个Matter fabric,每个fabric是独立的,但这里要强调的是,Matter支持一个设备接入多个fabric,也就是可以同时用苹果Google亚马逊控制同一个Matter设备,比如门锁。

1.3 Matter数据模型(Data Model)和设备类型

如下为一个典型的data model表示:

 

Node

节点(Node)是一个逻辑上独立的设备,有自己唯一的网络地址。每个Matter设备由一个或多个Node组成。

Endpoint

一个Node包含多个Endpoint,每个endpoint是一个逻辑上独立的功能模块。比如门锁,它除了可以包含门锁这个endpoint外,它还可以包含温度传感器这个endpoint。

注意:endpoint 0预留为Matter的utility cluster,而且每个Matter设备都必须强制包含它。

Cluster

Endpoint由一个或多个cluster组成,cluster可以认为是一个基本功能集,它包含attributes, commands和events三个组件。比如前面说的门锁endpoint,它除了可以包含Door Lock这个cluster外,它还可以包含Identify cluster以实现辨识功能。

Matter定义了两种类型的Cluster:

Server –提供Attributes, Commands和Events

Client – 对Server发起交互(interaction)操作

Cluster的详细规格定义请参见Matter Application Cluster Specification。如何通过cluster组成endpoint,进而组成设备类型,这个则是Matter Device Library Specification规定的内容。

Attribute

Attribute就是一条条表示物理量或者状态的数据记录,他们保存在设备的存储器中。

Command

Command就是下文所说的action,用来触发server的特定行为,比如关锁命令用来触发关锁操作。

Event

Event其实是一种特殊的attribute,它用来更新设备的状态,因此你可以把event当成是一种历史数据记录。

1.4 Matter交互命令和模型(Interaction Model)

通俗地讲,Interaction model就是用来规定交互命令集的,我们把发起交互的节点叫initiator (一般都是client设备),而接收者称为target (一般为server设备)。

Matter定义了如下interaction类型:

Read

用来读取attributes或events的值

Write

用来修改attribute的值

Invoke

用来发送commands

Subscribe

用来订阅target的数据报告,从而不用定时去查询相关数据,我们可以订阅attribute,也可以订阅event。

Interaction本身由transaction组成,而transaction又由action组成,每个action包含1条或者多条信息,如下:

 

下面我们以门锁为例子来具体讲讲interaction模型。

1.4.1 Interaction例子:门锁

下面例子假设initiator为Matter controller,target为door lock。

Read interaction

如下为读取DoorLock cluster 中的LockType attribute 的交互图:

 

Write interaction

如下为修改DoorLock cluster 中的OperatingMode attribute的交互图(修改为privacy模式意味着门锁只能从建筑内打开):

 

Invoke interaction

如下为调用DoorLock cluster的UnlockDoor command的交互图,其中Timed request用来定时命令的有效时间,为可选项。

 Subscribe interaction

如下为订阅DoorLock cluster 的LockState attribute状态值的交互图,这是一个持续进行的交互,除非一方停止或者返回失败。

  

1.5 Matter网络安全

Matter使用128-bit AES-CCM 算法来加密数据,为了得到AES密钥,根据两种不同的应用场景,Matter定义了两种会话(session)建立方式:Passcode-Authenticated Session Establishment (PASE)和Certificate-Authenticated Session Establishment (CASE)

1.5.1 PASE

PASE仅用于配网(commission)过程中,SPAKE2+算法通过8位passcode来建立一个安全通道,为了减轻设备端计算负担,可以直接把离线计算好的SPAKE2+ Verifier用来验证passcode。

1.5.2 CASE

CASE用于正常业务通信过程中,CASE是建立在前面配网成功基础上的,配网成功后,节点会得到一个节点操作证书(Node Operational Certificate,NOC)。当两个节点使用CASE进行通信时,他们的NOC必须共用同一个根证书,也就是他们必须属于同一个Fabric。有了NOC,就可以使用SIGMA算法来得到前述AES密钥了。

需要注意的是,Matter message包含如下元素:

Message Header – 会话和传输有关的信息

Protocol Header – Matter消息的语义规定

Payload – 真正的内容

虽然AES-CCM算法可以保证三个元素的完整性,但是只有Protocol Header和Payload会加密。

1.6 Matter网络配网

Matter配网(commissioning)就是把一个设备加入Matter Fabric(也叫Matter操作网络)的过程,此过程包含两个角色:

Commissioner device,一般放在Matter controller中,用于发起配网过程。

Commissionee device,就是还未添加到Matter网络中的设备。

为了完成配网,commissionee必须提供如下onboarding信息:

  • 16-bit Vendor ID and 16-bit Product ID
  • 12-bit device discriminator
  • 27-bit setup passcode
  • 8-bit Discovery Capabilities Bitmask

上面这些信息可以以下面三种方式提供:

  • 手动配对码(Manual Pairing Code)
  • 二维码(QR Code)
  • QR Code Payload

双方必须支持Manual Pairing Code,但推荐使用二维码,当然各个生态系统也可以定义自己的discriminator和setup passcode。

配网流程如下图所示:

 

如果上述配网流程成功,那么设备将得到如下信息:

  • 由fabric ID和node ID组成的实例名
  • Node Operational Certificate(NOC)
  • NOC对应的私钥
  • Access Control List
  • 操作网络的其他信息

1.7 Matter重要概念介绍

1.7.1 Matter Node(节点)

Matter node就是一个Matter设备的实例,一个Matter设备有可能包含一个或多个node,每个node通过64bit的node id来标识。我们也可以把不同的node组成一个group,并用16bit的group id来标识。

1.7.2 Matter controller(控制器)

Matter controller也是Matter网络的一个节点,它可以远程配置和控制附件设备,如下为两种典型的controller。

 

PC机中我们常见的controller就是CHIP Tool,当然Android或者iOS也支持CHIP Tool,开发者在调试Matter设备的时候,用得最多的就是CHIP Tool,如何在各大平台中配置和使用CHIP Tool,大家可以参考https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/matter/getting_started/testing/index.html#ug-matter-gs-testing

对于商用Matter生态系统,controller是一个组合体,比如苹果Matter生态,它的controller应该是iOS里面的Home app和HomePod音箱的组合体

1.7.3 Matter Fabric(网络)

一个Matter Fabric就是一个Matter网络,一个Matter Fabric中的所有节点共享同一个根证书,所以他们可以相互通信,每个Matter Fabric会分配一个64bit的ID进行标识。一般来说,一个Matter生态就是一个Matter fabric,比如苹果的Home就是一个fabric,谷歌的home又是另一个fabric。

1.7.4 Multi-fabric/multi-admin接入多生态

一个Matter node(节点)可以接入一个Matter fabric,也可以同时接入多个Matter fabric,比如同时被苹果/谷歌/亚马逊的音箱控制,这个特性就称为multi-fabric或者multi-admin。Multi-fabric将保证不同的生态可以相互兼容,提高Matter应用的互联互通性能。

1.7.5 Matter bridge

智能家居是一个非常碎片化的市场,除了Matter技术外,还有很多其他技术运用在智能家居市场中,比如蓝牙和ZigBee。为了将这些现有的智能家居产品一揽子接入Matter生态,Matter规范里面提出了Matter Bridge这个设备类型,通过Matter bridge,我们可以把非Matter设备快速接入Matter生态。如下网络拓扑结构演示了如何将一个蓝牙灯泡接入Matter网络,然后Matter controller像控制正常Matter设备一样去控制它。

  

1.7.6 Matter标准OTA

Matter规范要求设备必须支持设备升级功能,虽然Matter定义了一整套设备升级标准,但Matter没有强制规定设备必须采用这套标准的OTA升级方式,也就是说设备也可以采用其他方式来升级,比如使用基于蓝牙或者Wi-Fi的SMP方式进行升级。

Matter标准OTA定义了两个角色:OTA Provider和OTA Requestor,OTA Provider和OTA Requestor都是cluster,因此他们都有client和server角色之分,要升级固件的设备叫OTA requestor,而提供固件的设备(比如controller)叫OTA provider。

1.7.7 Distributed Compliance Ledger(DCL)

通俗地说,DCL是CSA运营的一个分布式数据库服务器,既然DCL是一个记账簿,它不会不断地更新和发展的。每当成员公司有新品发布,他们就会把这个新品的认证信息写到DCL中。如果颁发了新的PAA证书,这个信息也会写入DCL中。前面提及的Matter标准OTA,新image的URL信息也可以写入到DCL中。CSA也可以撤销或者作废DCL中的一些证书或者认证信息。总之,DCL就是一个分布式数据库服务器,保证了PKI系统的正常运行,同时也保证了Matter各个生态的互联互通。

1.7.8 Certificate Declaration(CD)

每当一个产品通过了Matter认证,CSA就会颁发一个CD证书给它,CD证书包括Vendor ID,Certificate ID,certification type等,由于一个产品类别下所有设备共用同一个CD,因此CD都是hard code在应用中的。

2. 支持Matter的nRF设备介绍

2.1 Matter over Thread nRF设备

Nordic支持Matter over Thread应用的SoC主要包括nRF54L15, nRF54L10, nRF54H20, nRF5340, nRF52840等。

2.1.1 nRF54L15主要特性

  • 1.5 MB NVM和 256 KB RAM
  • 128MHz Arm Cortex-M33 应用处理器
  • 128MHz RISC-V处理器
  • Bluetooth LE
  • Matter
  • Bluetooth mesh, Thread, Zigbee
  • Channel Sounding, Direction Finding
  • ANT
  • NFC-A tag
  • PSA Level 3
  • 105 °C 扩展工作温度
  • 1.7-3.6 V 电源电压范围

开发nRF54L15应用时,在nRF Connect SDK中选择的开发板类型为:nrf54l15dk_nrf54l15_cpuapp或者nrf54l15dk_nrf54l15_cpuapp_ns

2.1.2 nRF5340主要特性

  • 带1 MB 闪存和 512 KB 内存的128/64 MHz Arm Cortex-M33 应用处理器
  • 带256 KB 闪存和 64 KB 内存的64 MHz Arm Cortex-M33 网络处理器
  • 低功耗蓝牙
  • 蓝牙测向
  • Matter
  • Bluetooth mesh, Thread, Zigbee
  • ANT
  • NFC-A tag
  • 高级安全性
  • USB, QSPI, HS-SPI
  • 105 °C 扩展工作温度
  • 1.7-5.5 V 电源电压范围

开发nRF5340应用时,在nRF Connect SDK中选择的开发板类型为:nrf5340dk_nrf5340_cpuapp

2.1.3 nRF52840主要特性

  • 64 MHz Arm Cortex-M4 带FPU
  • 1 MB闪存 + 256 KB RAM
  • 低功耗蓝牙,蓝牙mesh
  • 2Mbps
  • 2.4 GHz 收发器
  • ANT, 802.15.4, Thread, Zigbee
  • 长距离
  • +8 dBm 发射功率
  • -95 dBm 灵敏度
  • 支持IEEE 802.15.4无线电
  • Matter
  • Thread
  • Zigbee
  • 1.7V至5.5V供电电压范围
  • 全速12 Mbps USB
  • NFC-A tag
  • PWM
  • UART, SPI, TWI, PDM, I2S, QSP
  • 高速 32 MHz SPI
  • Quad SPI 接口32 MHz
  • 12位/200 ksps ADC
  • 128位 AES CCM, ARM CryptoCell
  • USB 2.0

开发nRF52840应用时,在nRF Connect SDK中选择的开发板类型为:nrf52840dk_nrf52840

2.2 Matter over Wi-Fi nRF设备

要实现Matter over Wi-Fi应用,需要同时使用nRF5340和nRF7002/nRF7001两款芯片,nRF7002/nRF7001是Wi-Fi 6协同IC,他们只运行Wi-Fi有关的MAC层,Matter的其他部分还是跑在nRF5340上。

2.2.1 nRF7002主要特性

  • Wi-Fi 6站点(STA)
  • 2.4 GHz和5 GHz双频段
  • 符合802.11a/b/g/n/ac/ax标准
  • 用于物联网的低功耗安全Wi-Fi
  • 与低功耗蓝牙的理想共存
  • 目标唤醒时间(TWT)
  • SPI / QSPI
  • 1个空间流(SS)
  • 20MHz通道带宽
  • 64 QAM (MCS7),86 Mbps PHY
  • OFDMA(下行链路和上行链路)
  • BSS着色
  • 共存接口
  • nRF Connect SDK提供支持

开发nRF5340+nRF7002应用时,在nRF Connect SDK中选择的开发板类型为:nrf7002dk_nrf5340_cpuapp

2.2.2 nRF7001主要特性

nRF7001跟nRF7002功能差不多,但它只支持2.4G频段,不支持5G频段。

3. nRF Connect SDK和Matter SDK

开发Matter应用,你可以选择Nordic自己的SDK:nRF Connect SDK来开发,也可以选择Matter官方SDK:Matter SDK来开发。其实两套SDK基本上差不多,并且是相互包含的关系,也就是说,nRF Connect SDK里面已经包含了Matter SDK,站在nRF Connect SDK角度来看,Matter SDK就是它的一个模块。同样,Matter SDK里面也包含了nRF Connect SDK,站在Matter SDK角度来看,nRF Connect SDK就是它的一个模块。由于两者的互包含关系,导致两者的版本无法同步,也就是说,当nRF Connect SDK开始下一个版本开发的时候,它会锁定Matter SDK一个版本,比如nRF Connect SDK v2.5.0开发的时候,由于Matter SDK v1.2.0.0还没有发布,因此它锁定的版本就是Matter SDK v1.1.0.1;同样当Matter SDK v1.2.0.0开始开发的时候,由于nRF Connect SDK v2.5.0还没有发布,因此它锁定的版本就是nRF Connect SDK v2.4.0。这就导致一个现象,Matter SDK锁定的nRF Connect SDK版本总是落后于Nordic最新版本,nRF Connect SDK锁定的Matter SDK版本也总是落后于Matter官方最新版本。

如果你是做一个商业产品开发,强烈建议你使用nRF Connect SDK来进行开发,因为每个nRF Connect SDK版本的发布都会对Matter所有例子进行考核和测试,以保证他们的质量和稳定性,这也是为什么nRF Connect SDK会对Matter SDK打很多补丁以保证其质量。而且nRF Connect SDK同时支持Windows/MacOS/Linux平台,让你不再局限于Linux开发平台(经过一定修改后,我们也可以让Matter SDK跑在Windows平台,下文会对此进行介绍)。

如果你想测试Matter最新的特性,而这个特性nRF Connect SDK暂时又没有,那么可以使用Matter SDK来进行开发和调试,待下版本nRF Connect SDK包含了该特性,你就可以直接移植过去,快速发布你的产品。

欲查看Matter SDK锁定的nRF Connect SDK版本,大家可以打开这个文件:config/nrfconnect/.nrfconnect-recommended-revision,如下:

 

由于nRF Connect SDK会对它锁定的Matter SDK版本进行修改,我们没办法一眼看出它锁定的版本,但是大家可以从如下网站找到每个版本的nRF Connect SDK锁定的Matter SDK版本以及它遵守的Matter规范版本。

https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/matter/index.html 

虽然nRF Connect SDK和Matter SDK相互包含,但他们使用同一套工具链,而且这套工具链是伴随nRF Connect SDK一起下载和安装的,另外,不管你使用Matter SDK来开发Matter应用还是使用nRF Connect SDK来开发Matter应用,nRF Connect SDK都必须下载和安装,下面我们会以nRF Connect SDK为主来讲解Matter应用开发流程,然后在此基础上再讲解Matter SDK开发Matter应用的流程。实际上,你只要熟悉了nRF Connect SDK开发流程,也就熟悉了Matter SDK开发流程,因为两者几乎一模一样。

4. nRF Connect SDK开发环境搭建

关于nRF Connect SDK搭建和介绍,这里有一篇博文:https://www.cnblogs.com/iini/p/14174427.html,推荐大家去看一下。下面我们会对博文内容进行浓缩,简要介绍nRF Connect SDK。

4.1 前置安装

在我们开始正式的开发环境配置之前,我们先需要下载如下工具:

4.2 VS Code开发环境搭建

Microsoft Visual Studio Code(VS Code)是Nordic推荐的开发nRF Connect SDK应用的跨平台IDE工具,所以nRF Connect SDK开发环境搭建都是在VS Code中进行的。

4.2.1 插件安装

首先下载相应的插件。打开VS Code,进入Marketplace,搜索“nrf”,然后选择“nRF Connect for VS Code Extension Pack”进行安装,一旦nRF Connect for VS Code Extension Pack安装成功,所有nRF插件都自动安装成功。目前Nordic开发了如下nRF插件:

 

安装成功后,界面如下所示:

4.2.2 Toolchain安装

nRF Connect SDK开发使用的Toolchain可以通过VS Code直接安装,上面的nRF Connect for VS code插件安装成功后,点击左边的插件图标,进入WELCOME面板,然后选择Manage toolchains,在右边的列表框中选择Install Toolchain,如下: 

根据你选择的nRF Connect SDK版本选择对应版本的Toolchain,比如nRF Connect SDK v2.9.0对应的Toolchain如下所示: 

然后开始下载Toolchain,如下: 

下载成功后,自动解压和安装,如下: 

如下为安装成功的提示: 

这里需要注意的是,Toolchain安装可以不用VPN,但使用VPN可以让安装更稳定更可靠。

4.2.3 nRF Connect SDK安装

由于nRF Connect SDK放在GitHub服务器上,下载和安装nRF Connect SDK的时候请一定要使用VPN,否则很有可能就会下载不完整或者失败。

上面的nRF Connect for VS code插件安装成功后,点击左边的插件图标,进入WELCOME面板,选择Manage SDKs,然后在右边列表框中选择Install SDK,如下: 

 然后选择相应版本的nRF Connect SDK,如下: 

请注意,如果你是一个新用户,强烈建议你选择最新版本,即列表里面版本最高的版本,上面是v2.9.0,但是当你读到这时,最高版本有可能已经到v3.0.0,v4.0.0,甚至更高,请选择此时最高版本。

选择好版本后,然后选择SDK安装根目录,一般使用默认推荐的目录即可,如下。大家千万不要使用很长的目录作为安装根目录,否则在Windows上编译例子的时候,经常会碰到目录名太长的编译报错。 

然后VS code开始下载nRF Connect SDK,如下:

  

安装成功界面如下所示:

由于SDK放在Github上,经常碰到下载不完整的情况,而且这种情况又不会报错,为此我们可以通过下面的方式去检验nRF Connect SDK是否下载完整和正确,选择Manage west workspace,然后选择West Update,如下:

如果nRF Connect SDK已经完整下载并正确,此时在OUTPUT窗口,你将会看到下面的信息输出: 

如果nRF Connect SDK还缺少一些组件没有下载完整,此时在OUTPUT窗口,你将会看到类似下面这样的报错信息:

 

nRF Connect SDK和工具链安装成功后,都放在Windows如下目录里面:

 

可以看出,所有版本工具链都放在toolchains目录中,每个版本nRF Connect SDK放在以版本为名的目录中,比如v2.9.0。打开一个nRF Connect SDK目录,比如v2.9.0,可以看到nRF Connect SDK包含多个仓库,其中nrf是主仓库,而且nRF Connect SDK包含了Matter SDK仓库,Matter SDK仓库放在modules/lib/matter目录,如下:

至此,nRF Connect SDK开发环境已经搭好,下面我们来编译一个例子来验证一下开发环境是否真得搭成功了。

4.3 使用nRF Connect SDK编译Matter例程

nRF Connect SDK使用CMakeLists.txt文件来表示项目,并通过CMake命令来取代传统的通过GUI来添加源文件和目录,使用Kconfig来配置项目以取代传统的头文件配置方式,使用DeviceTree来配置底层驱动文件以取代传统的头文件配置方式,如果大家对CMake/Kconfig/DeviceTree不熟的话,建议阅读:https://www.cnblogs.com/iini/p/14174427.html,以加深对nRF Connect SDK的理解。

Matter项目很大,编译起来特别费时间,有时为了快速验证你的开发环境是否搭好,大家可以跑一个简单的例子,比如zephyr/samples/basic/blinky,以测试你的开发环境是否搭好。这里我们就不跑了,大家自己可以先测一下。下面我们为大家直接演示Matter例子是如何编译和运行的。

(注:如果你是中文Windows系统,编译nRF Connect SDK v2.9.0例子时,会报找不到板子错误,请将文件zephyr/scripts/list_boards.py第229行改成:"board yml.open('r'.encoding='utf-8')as f:",以解决这个编码错误

我们以nrf/samples/matter/lock为例,详细阐述如何使用nRF Connect SDK来编译和运行Matter例子。nrf/samples/matter/lock是一个门锁例子,同时支持Matter over Thread和Matter over Wi-Fi,如果你选择nrf54l15dk_nrf54l15_cpuapp,nrf5340dk_nrf5340_cpuapp或者nrf52840dk_nrf52840,那么这个例子自动编译成Matter over Thread应用;如果你选择nrf7002dk_nrf5340_cpuapp,那么这个例子自动编译成Matter over Wi-Fi应用。

下面我们以nrf52840dk_nrf52840为例(其他板子跟它一模一样),来编译和运行这个门锁例子。

为了浏览代码方便,可以先通过VS Code的File -> Open Folder打开nRF Connect SDK v2.9.0目录,如下:

选择APPLICATIONS标签页,选择Open Existing Application,如下:

 

选择目录:nrf/samples/matter/lock,如下:

 

打开上述项目后,将自动跳出Add Build Configuration页面,在Board列表框中,选择开发板:nrf52840dk_nrf52840,如下: 

由于前面已经打开了nRF Connect SDK v2.9.0目录,这里自动帮你选好了SDK版本和Toolchain版本,你可以根据自己情况选择合适的SDK版本和Toolchain版本。

然后选择Configuration文件,如果留空,默认选择prj.conf,大家也可以选择其他配置项。

 

其他一些配置项的说明如下所示:

 

选择Build Configuration,开始编译,视你的PC配置情况,编译有可能耗时达10分钟之久,编译成功后,你将看到如下输出:

  

整个VS code一览图如下所示:

 

至此,项目编译成功,大家可以点击“Flash”将代码下载到板子里面,然后Matter应用就自动跑起来了,打开PC串口助手,你将看到如下输出日志,说明Matter应用已经在正常运行了。 

5. Matter SDK开发环境搭建

如前所述,搭建Matter SDK开发环境之前,必须先搭建好nRF Connect SDK开发环境,请大家先按照第4章的要求,搭建好nRF Connect SDK开发环境,然后再来读这一章。

对绝大多数人来说,可以直接跳过这一章。

由于绝大多数人都不会用Matter SDK,我将不再对本章作任何更新和维护。

5.1 Matter SDK下载和安装

5.1.1 Matter SDK下载

Matter SDK是放在GitHub上的,因此必须使用VPN来下载Matter SDK。

首先,打开CMD,进入c:/ncs目录,然后输入如下命令:

git clone https://github.com/project-chip/connectedhomeip.git

 

上面命令将把Matter SDK公共的仓库都下载下来,而且自动切换到Matter SDK的master分支,如果你要切换到一个特定的tag,比如v1.2.0.1,请执行:

git checkout v1.2.0.1

 

由于Matter SDK支持众多平台和厂商,我们还需要下载这些第三方的仓库,为此,我们再输入如下命令:

cd C:/ncs/connectedhomeip/scripts
python checkout_submodules.py --platform nrfconnect

 

上面的platform参数来指明下载哪个平台或厂商的仓库,如果没有指明,说明下载所有平台或厂商的仓库,这个工作量是巨大的(目前是19GB左右),下载的时间也是很长的。上面的例子我们指明了nrfconnect平台,这就意味着它只会下载Nordic Matter开发相关的仓库,这个就小多了,大概1.5GB不到。

如果你之前已经安装过Matter SDK,现在只是想更新到最新版本,那么使用下面命令即可:

git pull
git submodule update --init

 

5.1.2 安装缺少的Python模块

然后我们还需要安装缺少的Python模块,这个是针对于nRF Connect SDK Toolchain来说的。nRF Connect SDK Toolchain是直接为nRF Connect SDK准备的,因此它不用做任何修改,就可以直接编译nRF Connect SDK例子,但对Matter SDK例子,它有一些额外的Python模块需求,因此我们需要将其补充完整。为了确保执行的是nRF Connect SDK Toolchain里面的Python,而不是操作系统环境变量中的Python,推荐大家使用VS code的终端来执行命令,即打开如下nRF Connect终端:

 

这样就保证了该命令行的环境是nRF Connect SDK Toolchain设置的环境,在该终端中执行的任何命令都是针对nRF Connect SDK Toolchain环境来说的

我们输入如下命令:

pip3 install -r C:/ncs/connectedhomeip/scripts/setup/requirements.build.txt

这样系统就会自动补全nRF Connect SDK Toolchain缺少的Python包,如下所示:

 

5.1.3 安装合适的zap工具

虽然前面nRF Connect SDK开发环境搭建过程中,已经安装好了zap工具,但是这个zap工具的版本有可能跟Matter SDK要求的zap工具版本不一样,为此我们还需要再安装一次期望版本的zap工具。

首先我们需要先确认zap工具的版本对不对,大家可以通过scripts/setup/zap.version这个文件确认:

 

这就意味着对Matter SDK v1.2.0.1来说,它需要的zap工具版本是v2023.10.24-nightly,然后大家可以到如下链接下载相应版本:https://github.com/project-chip/zap/releases,找到版本“v2023.10.24-nightly”,然后下载自己平台的安装包。

 

比如Windows,就下载zap-win-x64.zip这个压缩包,下载成功后,解压缩,将其放在某个目录下,然后把该目录添加到Path变量中,如下为我电脑上的解压缩路径和Path变量值:

 

 

如果你的PC安装有老的zap工具,那么请记得把上面的环境变量一定要指向你刚刚解压缩的目录,而不是原来的值。另外原来的zap工具会在如下目录生成一个缓冲文件:

 

为了更好的兼容性,大家可以把这个文件直接删掉

至此,Matter SDK已经下载和安装完毕,下面我们就可以开始用它来编译和运行Matter应用了。

5.2 编译Matter SDK例子

5.2.1 Linux/MacOS平台

原生的Matter SDK就支持Linux和MacOS平台,因此你不要做任何修改,你就可以在Linux和MacOS上编译Matter SDK例子,大家可以参考4.3节介绍的步骤,去编译Matter SDK里面的例子,比如examples\lock-app\nrfconnect,这个是Matter SDK里面自带的门锁例子。

5.2.2 Windows平台

由于前面已经把nRF Connect SDK开发环境搭建好,我们可以直接使用nRF Connect SDK开发环境来编译和运行Matter SDK例子,整个步骤跟前述的编译运行nRF Connect SDK例子一模一样。

5.2.2.1 修改Matter SDK以适配Windows平台

由于原生的Matter SDK只能在Linux和MacOS上进行编译,我们需要对原生的Matter SDK进行几处修改才能直接在Windows上进行编译,修改的地方如下所示:

  1. 在connectedhomeip/build_overrides目录下,新建一个空文件,文件名为:pigweed_environment.gni。这个文件创建一次就可以,然后可以适用所有Matter工程。
  2. 修改一些编译脚本。请大家将https://patch-diff.githubusercontent.com/raw/project-chip/connectedhomeip/pull/30982.diff对应的文件下载下来,命名为30982.diff,放在c:/ncs目录下,然后执行
    git apply c:/ncs/30982.diff

    就可以自动修改相应脚本以支持Windows,如下:注意:这个补丁是针对Matter SDK版本v1.2.0.1的,Matter SDK未来版本有可能会把这个PR合并进去,这样这个补丁就没有必要再打了。

  3. 修改每个项目的CMakelists.txt文件,只改一个地方:把本项目目录下的third_party\connectedhomeip这个文件包含的内容直接取代CMakelists.txt中的变量connectedhomeip,即把../../../..取代connectedhomeip,使get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/connectedhomeip REALPATH)这句话变成get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/../../../.. REALPATH)

5.2.2.2使用Matter SDK编译Matter例程

如果你前面没有选择Matter SDK的版本,那么你首先要checkout一个你期望的版本,一般选择一个tag来开发和测试,而且一般都是选择最新的tag来开发和测试,如下图所见,截止本文发表时,Matter SDK最新的tag是v1.2.0.1。

 

为此我们选择v1.2.0.1这个tag来演示我们下面例子的编译和测试。我们在CMD中输入如下命令:

git checkout v1.2.0.1
git submodule update

 

我们还是以Matter SDK原生的lock例子为例:connectedhomeip\examples\lock-app\nrfconnect,来阐述整个编译过程。

首先修改CMakelists.txt文件(前面说得pigweed_environment.gni这个空文件记得要先创建),得到:

  

然后像编译nRF Connect SDK例子一样去编译这个lock例子。由于Matter SDK使用了nRF Connect SDK的工具链,因此我们必须要知道当前Matter SDK锁定的nRF Connect SDK的版本是多少。查看Matter SDK要求的nRF Connect SDK版本,大家可以打开这个文件:C:\ncs\connectedhomeip\config\nrfconnect\.nrfconnect-recommended-revision,如下:

 

说明它要求的nRF Connect SDK版本是v2.4.0,接下来我们就要在WELCOME标签页中选择nRF Connect SDK v2.4.0以及对应的Toolchain,如下:

 

然后选择Open Existing Application,找到目录:connectedhomeip\examples\lock-app\nrfconnect,如下:

  

然后选择开发板:nrf52840dk_nrf52840

 

然后选择“Build Configuration”开始编译,编译成功后,将有如下输出日志:

 

点击Flash,将程序下载到开发板:

 

程序运行起来后,将有如下日志输出:

 

按下Button4,设备就会开始蓝牙广播,表示已经做好配网准备,可以接入Matter生态了:

 

下面我们就会讲解如何使用HomePod mini来测试Matter设备。

6. 使用苹果HomePod mini测试你的Matter设备

不管是用nRF Connect SDK编译的lock例程(4.3节),还是用Matter SDK编译的lock例程(5.2.2.2节),编译成功并运行后,他们的测试流程都是一样的。

首先确保设备进入了配网模式,即蓝牙广播已开启,日志有“advertising started”字样,如果没有开启,请按开发板Button1以激活蓝牙广播。

然后我们从日志中可以看到一个网址,如下: 

https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A8IXS142C00KA0648G00

将上面网址拷到浏览器中,即可以得到配网用的二维码,如下: 

目前Nordic所有例子默认都使用上面二维码来配网,大家只要扫描上面二维码就可以完成配网。

在开始下面的测试步骤之前,请确保你的HomePod mini和iPhone或者iPad连接同一个路由器,而且HomePod mini已经跟该iPhone或者iPad的Home app绑定好。

打开iOS设备上的Home app,点击右上角的“+”,选择Add or Scan Accessory,如下:

  

跳出下面的扫描窗口,将扫描窗口对准上面的二维码,扫描成功后,配网真正开始。

  

大家也可以从日志看出,配网流程正在进行中,下面就是截取配网流程的一个小片段的日志: 

过一会,iOS设备就会弹出如下对话框,这个是因为我们使用的是测试DAC证书和测试用PID等,请大家参考第8章如何获取生产用的证书和ID等信息,这里我们选择“Add Anyway”。

  

设备配网成功后,iOS设备会连续出现如下界面: 

选择这个设备所在的位置:

  

给这个设备取一个好记的名字:

  

如果是锁设备类型,还需要设置它的访问密码:

  

设置一些自动化的场景:

  

最后显示设备添加成功的界面,如下:

  

同时大家也可以从Home app的主界面看到这个添加成功的设备,如下:

  

除了从iOS设备上观察设备是否添加成功,你也可以从日志输出来佐证设备是否添加成功,设备添加成功后,你一般会看到如下红色标注的日志: 

设备添加成功后,我们就可以对设备进行各种操作,比如我们去开锁或者关锁,界面如下所示:

   

 大家除了可以从iOS设备看到开锁或者关锁成功的界面,也可以从输出的串口日志看到开锁或者关锁成功的标志,如下: 

我们现在结合本lock例子来看看Matter的数据模型长什么样。首先,在VS code中打开nRF Connect终端,并执行如下命令:

cd nrf/samples/matter/lock 
west zap-gui

上面命令会自动调用zap工具,并打开lock例子下面的zap文件。如果zap工具没有安装的话,本命令会自动帮你下载和安装zap工具,如下:

选择nrf/samples/matter/lock/src/default_zap/lock.zap文件,这个就是lock例子对应的ZCL格式的数据模型,成功后,你将看到:

其中,endpoint 0是每个设备必选的端点,而endpoint 1就是我们的门锁端点,右上角选择“Enabled Clusters”,你将看到门锁这个端点拥有3个cluster:Identify,Descriptor和Door Lock,Door Lock是我们的重点cluster。

7. 开始你的Matter定制开发之旅

Matter开发主要包括两方面的工作:一是Matter应用本身的开发,二是非Matter应用开发。Matter应用开发本质上就是cluster/endpoint/node的添加、编辑、删除以及相关回调事件处理等,如前所述,这个需要通过zcl编辑工具zap来生成ember层的代码,以及手动添加或者修改其他c++文件来实现,下面一一对此进行介绍。非Matter应用开发包括蓝牙服务,传感器应用开发等,这部分代码是用C语言撰写的。一般来说,Matter应用这块,大家都不要怎么动,直接使用SDK里面自带的例子即可,所以对大家C++编程能力要求并不高。大家绝大部分时间还是花在非Matter应用开发,这个是C语言编程要求,这个相信大家都很熟了。

开发的时候选择nrf/samples/matter里面某一个例子为开始点,比如门锁选择lock例子,窗帘选择window_covering;如果你的设备跟现有例子都不一样,那么可以以template为基础来开始

下面我们来做一个挑战,要求大家完成两项开发任务:一是添加Matter on/off light设备,二是添加蓝牙LBS服务(LED Button Service)。由于Matter on/off light设备没有现成例子,我们以nrf/samples/matter/template为基准来开发,为了不更改原始例子,我们将nrf/samples/matter/template整个目录拷贝出来,放在c:/ncs目录,并把目录名改为bulb:

7.1 添加Matter On/Off Light设备

7.1.1 添加cluster

如前所述,我们可以使用ZAP来添加endpoint和cluster。在我们这个项目里面,zap文件就是C:/ncs/bulb/src/default_zap/template.zap,template.zap是一个JSON文件,包含了应用所有的endpoint,cluster,attribute和command。我们可以使用如下命令打开这个zap文件:

cd C:/ncs/bulb
west zap-gui

 ZCL界面如下所示:

 

可以看出,例子目前只有Endpoint 0,选择Endpoint 0,并选择“Enabled Clusters”,我们可以看到这个Endpoint使能了哪些cluster,比如Descriptor cluster。

下面我们添加一个Endpoint以支持Matter On/Off Light设备,选择“ADD ENDPOINT”,在弹出的对话框中,选择“Matter On/Off Light”,如下:

 

创建成功后,点击“Endpoint -1”。请确认右边On/Off cluster已使能,然后点击配置图标。 

在弹出的对话框中,确认OnOff Attribute已经使能: 

同时确认Off和On命令已使能:

至此,我们的endpoint和cluster就添加成功了。

但上面的添加操作只是修改了zap文件,对我们SDK没有做任何修改。接下来,我们就要使用一个命令将这个zap文件转成相应的c++文件和头文件,以让这个修改操作可以编译到我们的代码中去。

cd C:/ncs/bulb
west zap-generate

 

至此,Matter On/Off Light设备已经添加到我们的应用中了。

7.1.2 修改项目代码

添加完cluster后,我们还需要修改项目代码,以让新添加的设备真正可以工作起来。这个工作主要包括两部分:

  • 添加Matter stack回调函数,以处理controller发送过来的命令,比如开灯。这个主要通过覆盖MatterPostAttributeChangeCallback()来实现
  • 更新attribute数值,以让Matter stack可以将最新的状态或者event同步给controller。这个主要通过Clusters::OnOff::Attributes::OnOff::Set()之类的函数实现。

首先我们先实现MatterPostAttributeChangeCallback(),新建一个文件:src/zcl_callbacks.cpp,然后将如下代码拷入: 

复制代码
#include "app_task.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;

void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type,
                                       uint16_t size, uint8_t * value)
{
        if (attributePath.mClusterId != OnOff::Id || attributePath.mAttributeId != OnOff::Attributes::OnOff::Id)
                return;

        AppEvent event;
        if (*value) {
            event.Type = AppEventType::TurnOnLED;
            event.Handler = AppTask::TurnOnLEDHandler;
        }
        else {
            event.Type = AppEventType::TurnOffLED;
            event.Handler = AppTask::TurnOffLEDHandler;
        }
        AppTask::Instance().PostEvent(event);
}
复制代码

本来代码逻辑可以更简单,当收到On命令时,调用sBulbLED.Set(true)开灯;收到Off命令时,调用sBulbLED.Set(false)关灯。但这种做法会影响Matter协议栈的行为,因此我们把sBulbLED.Set()操作扔到一个event queue中去执行,而AppTask正好有一个现成的sAppEventQueue,我们正好可以加以利用,这样当收到On命令时,我们把TurnOnLED事件扔到Event queue,然后在AppTask主循环中取出该事件,并调用该事件的handler:TurnOnLEDHandler。Off命令的处理情况也类似。我们在app_task.cpp加入如下代码: 

复制代码
void AppTask::TurnOnLEDHandler(const AppEvent &)
{
    LOG_INF("TurnOnLEDHandler");
    sBulbLED.Set(true);
}

void AppTask::TurnOffLEDHandler(const AppEvent &)
{
    LOG_INF("TurnOffLEDHandler");
    sBulbLED.Set(false);
}
复制代码

其中sBulbLED定义如下:

LEDWidget sBulbLED;

我们同时在AppTask::Init()中对其做如下初始化:

sBulbLED.Init(DK_LED2);
sBulbLED.Set(false);

然后不要忘了在app_task.h中声明TurnOnLEDHandler和TurnOffLEDHandler,如下:

static void TurnOnLEDHandler(const AppEvent &);
static void TurnOffLEDHandler(const AppEvent &);

为了让app_task.cpp访问cluster attribute,比如Clusters::OnOff::Attributes::OnOff::Set(),需要加入如下头文件:(注:本文我们并没有调用Clusters::OnOff::Attributes::OnOff::Set(),但实际应用肯定会调用它的)

#include <app-common/zap-generated/attributes/Accessors.h>

最后我们把src/zcl_callbacks.cpp文件添加到CMakeLists.txt,如下:

至此,整个项目开发就算结束,下面我们就来测试我们这个新项目吧。

7.1.3 测试

我们可以按照第6章的方式,测试这个新的Matter设备,这里就不再赘述了。设备配网成功后,iOS Home app将会看到如下设备:

 

操作灯泡的界面如下所示:

 

7.2 添加蓝牙LBS服务(LED Button Service)

在nRF Connect SDK中,Matter相关代码都是用C++撰写的,除此之外,其他代码都是使用C代码编写的。两者浑然一体,各自运行良好。因此,我们只要参考nrf/samples/bluetooth/peripheral_lbs这个例子,就可以把LBS服务加入到例子中。

首先将nrf/samples/bluetooth/peripheral_lbs下面的main.c改名为lbs.c,拷贝到项目的src目录下,并修改CMakelists.txt: 

然后我们需要对lbs.c文件作几处修改,由于Matter例程已经调用了main(),将lbs.c里面的main()改为普通线程,并删掉重复初始化函数,实际上只需要保留bt_lbs_init()这一个初始化函数,如下:

 

由于Matter应用和lbs.c中都使用了LED模块,为了有一个更好的直观效果,我们把lbs.c中的

#define RUN_STATUS_LED          DK_LED1

#define CON_STATUS_LED          DK_LED2

改成

#define RUN_STATUS_LED          DK_LED4
#define CON_STATUS_LED          DK_LED4

将CONFIG_BT_LBS=y和CONFIG_BT_LBS_POLL_BUTTON=y 加入到prj.conf

CONFIG_BT_LBS=y
CONFIG_BT_LBS_POLL_BUTTON=y

至此项目代码修改完毕,我们可以编译了,编译成功后,下载代码到板子中,打开手机app:nRF Connect,将看到如下广播:

 

点击“CONNECT”,连接成功后,我们将看到LBS服务,如下:

 

然后我们可以对LED这个特征进行操作:ON或者OFF,板子上的LED4将跟随命令而变化。

 

7.3 C代码与C++代码混合编程

7.3.1概述

从上面例子大家可以看出,添加Matter设备的时候,我们使用的是C++代码;添加蓝牙LBS服务的时候,我们使用的是C代码。一个工程中同时存在C和C++代码,这是Matter应用一个非常突出的特性,这就要求我们既需要理解C语言代码,也需要了解一定的C++代码,所以Matter开发是一个比较复杂而富有挑战的工作。

在Matter开发中,大家碰到一个很常见的问题是:如何让C代码调用外部C++代码编写的API,或者如何让C++代码调用外部C代码编写的API。

关于C++代码调用外部C代码API,前面其实已经出现过多次,这个跟C代码调用C代码API一模一样,比如在app_task.cpp中,调用了如下外部C语言API:dk_buttons_init,k_msgq_get,k_timer_start等,可以看出跟普通调用几乎没有区别。

关于C代码调用外部C++代码API,这个处理起来就稍微复杂一些。如果C代码只是调用一个全局的C++函数,那么我们需要把该函数申明为extern "C",然后就可以被C代码调用了;但是C编译器又不识别extern "C",因此我们一般在头文件中使用如下申明:

 

其中start_lbs_adv()就是一个可以被C调用的C++函数。

还有一种情况,就是C要调用C++类里面的函数,这个时候我们就需要先获得类对应的实例,然后通过实例去引用本实例自身的函数。如何获得实例的引用是整个调用最关键的部分,好在Matter应用中,我们使用了Singleton(单例)模式,也就是说每个类只会创建一个静态的全局实例,这也就意味着类函数调用跟全局函数调用差不多,通过这个静态全局实例,我们就可以调用类里面任何公共(public)函数,比如类AppTask,它的静态全局实例可以通过AppTask::Instance()获得,得到这个实例后,我们就可以调用AppTask里面任何公共函数了,比如StartApp(),这样完整调用例子就变成:AppTask::Instance().StartApp()。

由于我们不会去更改SDK任何原始代码,我们需要建一个CPP文件作为桥梁去调用其他CPP文件里面的API,这样就可以保证SDK原始的CPP文件不会动,我们只需要修改该新建的CPP文件就可以完成我们的目标。

下面我们结合实际应用场景来看看C和C++是如何相互交互的。还是以上面的工程为例,我们要添加两项工作:一是增加LBS原始的广播,二是当Button状态变化时,通知到手机app。

7.3.2 C调用外部C++函数示例

本来启动广播直接调用bt_le_adv_start()即可,为了演示C调用外部C++ API,这次我们通过调用BLEAdvertisingArbiter::InsertRequest来实现。

首先我们新建两个文件:lbs_adv.cpp和lbs_adv.h,在lbs_adv.h我们定义如下可以被C调用的C++ API: 

复制代码
#pragma once

#ifdef __cplusplus
extern "C"
{
#endif

void start_lbs_adv();

#ifdef __cplusplus
}
#endif
复制代码

然后我们在lbs_adv.cpp中实现start_lbs_adv(),实现代码如下所示: 

复制代码
/*
 * Copyright (c) 2021 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include "lbs_adv.h"
#include <platform/Zephyr/BLEAdvertisingArbiter.h>
#include <lib/support/Span.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <bluetooth/services/lbs.h>
#include <array>

#include <zephyr/logging/log.h>

using namespace ::chip;

constexpr uint8_t kAdvertisingFlags    = BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR;
constexpr uint8_t serviceData[] = {BT_UUID_LBS_VAL};
constexpr uint8_t name[] = "LBS_ADV";

void lbs_adv_started(int rc)
{
    printk("LBS advertising started:%d\n", rc);
}

void lbs_adv_stopped()
{
    printk("LBS advertising stopped\n");
}

void start_lbs_adv()
{
    static std::array<bt_data, 2> advertisingData;
    static std::array<bt_data, 1> scanResponseData;
    static chip::DeviceLayer::BLEAdvertisingArbiter::Request lbsAdvRequest = {};

    advertisingData[0]  = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags));
    advertisingData[1]  = BT_DATA(BT_DATA_NAME_COMPLETE, name, sizeof(name));
    scanResponseData[0] = BT_DATA(BT_DATA_UUID128_ALL, serviceData, sizeof(serviceData));
    lbsAdvRequest.priority    = 2;
    lbsAdvRequest.options     = BT_LE_ADV_OPT_CONNECTABLE;
    lbsAdvRequest.minInterval = 360;
    lbsAdvRequest.maxInterval = 500;
    lbsAdvRequest.advertisingData  = Span<bt_data>(advertisingData);
    lbsAdvRequest.scanResponseData = Span<bt_data>(scanResponseData);
    lbsAdvRequest.onStarted = lbs_adv_started;
    lbsAdvRequest.onStopped = lbs_adv_stopped;

    chip::DeviceLayer::BLEAdvertisingArbiter::InsertRequest(lbsAdvRequest);    
}
复制代码

可以看出start_lbs_adv()最终调用了Matter C++库函数:BLEAdvertisingArbiter::InsertRequest()。

最后我们在lbs.c文件中调用start_lbs_adv(),这样当Matter配网广播超时之后,我们的LBS广播就会自动启动。为了更快地观察到效果,大家可以把modules\lib\matter\src\include\platform\CHIPDeviceConfig.h中的CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS定义做如下修改:

#define CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS (3 * 60)

将编译成功的代码烧录到板子,3分钟超时过后,大家可以看到如下广播:

 

同时串口日志会有如下显示:

 

这个时候我们点击“CONNECT”,连接这个设备,会发现设备只包含LBS服务,之前的CHIPoBLE配网服务由于超时已经被解除注册了,如下:

 

7.3.3 C++调用外部C函数示例

现在我们完成第二个工作:当Button状态变化时,通知到手机app。

这个工作在原始的peripheral_lbs例程中,是通过在button_changed回调函数中调用bt_lbs_send_button_state()实现,由于在app_task.cpp中我们已经实现了按键的回调函数:AppTask::ButtonEventHandler,我们将在AppTask::ButtonEventHandler中调用bt_lbs_send_button_state()来实现我们的目的。

首先在app_task.cpp中包含如下文件:

#include <bluetooth/services/lbs.h>

然后直接在AppTask::ButtonEventHandler中调用bt_lbs_send_button_state(),如下:

 

至此,代码已全部更改完毕。可以看出C++调用外部C函数的确比较简单,没有任何多余的操作。

再次编译代码,并将新程序烧录到板子中。跟前面操作一样,通过手机app:nRF Connect连上板子后,并使能Button特征对应的CCCD,然后我们按下或者松开板子上的按键1,手机app的Button特征值会跟随一起变化,如下:

  

8. Matter产品量产注意事项

nRF Connect SDK或者Matter SDK例子默认配置都是开发者模式,这种模式是不能量产的。因此,在产品量产之前,我们还需要做一些额外的配置。

8.1 Matter认证(Certification)

纯蓝牙或者Wi-Fi产品,即使不通过认证,也是可以量产的,因为蓝牙和Wi-Fi更强调他们的连接标准性。跟纯蓝牙或Wi-Fi标准不一样,Matter是一个应用级别的标准,而且Matter使用了PKI技术进行鉴定(authenticate),这就意味着Matter产品必须经过认证(certification),才能确保产品的互联互通性。

对于蓝牙和Wi-Fi新产品认证,如果它完全继承芯片原厂或者模块商的认证,那么它是可以免除ATL实验室的测试。对于Matter新产品,它必须经过ATL实验室的测试,然后才能获得认证证书。当然Matter也有快速认证,前提是你必须有一款产品已经获得过认证,新产品是在已认证产品的基础上做微小改动情况下,才能免除ATL实验室的测试。

前面也提及过,过Matter认证之前,你必须先确保你的产品已经通过蓝牙和Thread或Wi-Fi认证。而且要获得产品认证资格,你还必须加入相关联盟,这也会产生一定费用。

关于Matter认证的详细说明,请参考:https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/matter/end_product/certification.html

Matter认证过程中,有一份PICS文件非常重要,这个需要你提交给ATL和CSA。关于如何生成自己产品对应的PICS文件,还是请参考上面链接。

8.2 生态系统的认证

获得了Matter认证,就意味着你的产品跟所有Matter生态都是互联互通的。由于种种原因,每个生态还有自己的认证,比如Apple有Works with Apple Home认证,Google有Works with Google Home认证,Amazon有Frustration-Free Setup(FFS)认证。这些认证其实不是必须的,看大家的意愿去选择要不要过这些认证。具体请见:https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/matter/end_product/ecosystems_certification.html

8.3 Certification Declaration(CD)固化

当你通过了CSA的Matter认证后,CSA会颁发一个CD证书给你。按照Matter规定,你每升级一次固件,都需要重做一次认证(这个认证是免费的哦),每重做一次认证,CSA都会颁发一个新的CD证书给你,然后你通过OTA把这个新CD取代老CD。

CD一个最重要的作用,就是在设备配网过程中,充当设备自证(Device Attestation)申明。因此我们需要把CD和固件一起烧入到设备中。最简单的方法,就是定义一个宏,固化到固件中,但这种方法无法更新CD。还有一种方法,就是把CD放在一个特殊Flash区域,比如Settings或者NVS区域,这样我们就可以通过Settings或者NVS API更新它。更多细节请见:https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/matter/end_product/configuring_cd.html

8.4 如何获取PAI和DAC证书/私钥

DAC,全称Device Attestation Certificate,即设备自证证书,DAC证书和DAC私钥对每个设备来说都是唯一的,也就是大家常说的“一机一密”。PAI,全称Product Attestation Intermediate,一般一个产品类别对应一个唯一PAI,每个产品下面有许许多多的设备,所以PAI是用来签署前面的DAC证书的。

对于量产产品来说,你只能使用CSA认证过的CA机构签发的PAI以及DAC公私钥对,大家可以联系CSA授权的CA机构去购买相应证书和密钥。

在产品开发过程中,如果你不想使用SDK默认的测试证书,那么也可以通过chip-cert来生成自己的测试证书,具体请参见8.3节和8.5节的两个链接里面的介绍。

8.5 Factory data烧写

Matter产品量产的时候,有很多信息需要烧入到设备中,并且整个产品生命周期不再会改变,这些信息就称为出厂数据(factory data)。对于Matter设备来说,前面所述的DAC证书,PAI证书,供应商ID,产品ID,序列号,配网信息等,都属于出厂信息。

为了保证大家可以生成自己需要的factory data,以及把这些factory data正确烧入到设备中,nRF Connect SDK准备了一个Python脚本:generate_nrfconnect_chip_factory_data.py,用来生成JSON格式的出厂数据/配对码/配对二维码,以及转成相应hex文件,这样就可以通过nrfutil/nrfjprog等J-link工具把hex文件烧入到设备中。

具体来说,我们可以按照下面步骤来完成出厂数据烧写工作:

  • 首先编译的时候确保SB_CONFIG_MATTER_FACTORY_DATA_GENERATE=n加入到sysbuild.conf中,然后prj.conf有如下配置:
CONFIG_CHIP_FACTORY_DATA=y
CONFIG_CHIP_FACTORY_DATA_BUILD=n
CONFIG_NCS_SAMPLE_MATTER_TEST_EVENT_TRIGGERS_REGISTER_DEFAULTS=n
CONFIG_NCS_SAMPLE_MATTER_TEST_EVENT_TRIGGERS=n
  • 打开VS Code的nRF Connect终端,然后输入如下命令:
cd modules/lib/matter
python scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py --sn "99887766554433221100" --vendor_id 65521 --product_id 32774 --vendor_name "Nordic Semiconductor ASA" --product_name “bulb" --date "2025-01-15" --hw_ver 1 --hw_ver_str "prerelase" --dac_cert "credentials/development/attestation/Matter-Development-DAC-FFF1-8006-Cert.der" --dac_key "credentials/development/attestation/Matter-Development-DAC-FFF1-8006-Key.der" --pai_cert "credentials/development/attestation/Matter-Development-PAI-FFF1-noPID-Cert.der" --spake2_it 1000 --spake2_salt "U1BBS0UyUCBLZXkgU2FsdA==" --discriminator 0x666 --generate_rd_uid --rd_uid e2eb609c5a793e5e9de536c211246a2e --include_passcode --passcode 666888 --product_finish "matte" --product_color "black" --out "c:/ncs/bulb/factory_data.json" --schema "scripts/tools/nrfconnect/nrfconnect_factory_data.schema" --offset 0xf7000 --size 0x1000 --generate_onboarding --overwrite

 注意:上面的DAC和PAI还是测试用证书,记得换成自己购买的证书。sn/vendor_id/product_id/vendor_name/discriminator/passcode/spake2_it/spake2_salt等等其他参数也需要按照你们的需求做相应调整,参数offset和size由下面分区文件决定: 

整个命令的执行日志如下所示:

  • 把上述生成的出厂数据烧录到设备中,这可以通过nrfutil或者nrfjprog命令实现:
nrfjprog -f nrf52 --program c:/ncs/bulb/factory_data.hex --sectorerase --verify --reset
nrfutil device program --firmware c:/ncs/bulb/factory_data.hex

执行结果如下所示: 

 这时,观察串口日志,我们发现设备的配网信息已发生改变,如下: 

关于如何生成和烧写出厂信息,详细说明请参考:

https://docs.nordicsemi.com/bundle/ncs-latest/page/matter/nrfconnect_factory_data_configuration.html

 

####################### The END (完) ################################### 

posted on   iini  阅读(11176)  评论(4编辑  收藏  举报

相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示