一. 写在前面
在之前的博客文章 《基于乐鑫 ESP32-C3 的 Matter Light 实践》中,我们利用乐鑫的硬件和 SDK 方案实现了简单的 Light 例程,并对 Matter 协议进行了简要介绍。在开始本篇文章之前,我还是打算重新聊一聊 Matter,顺便谈谈自己对它的理解,这也能说明为何这段时间我一直执着于这个事情。
1.1 Matter 的诞生背景
其实说到智能家居这个领域,我们应该能联想到很多目前做的不错的品牌,比如国内的华为、绿米 Aqara、欧博瑞,海外的 APPLE、Google Nest 等等。同时,它们又有着自己的一套生态协议,就像 Apple 有 Homekit、Amazon 有 alexa、华为有 Hilink 一样。
这些生态本身的发展,从今天来看都是比较成熟的。但是对于消费者和制造商来说,可能会面临一些头疼的情况:
(1)对于消费者:家里装了多个生态的产品,比如小米的灯和传感器、华为的门锁以及苹果的音响,这意味着你想要管理它们就不得不使用各自的应用程序,同时在这种场景下构建家庭自动化也会困难重重。当然,可能有人会说引入一个 Home Assistant 网关来尝试解决这些问题,这对部分 Geeker 来说是没有问题的,但是面对与普通消费者,这无疑提高了很高的使用门槛。
(2)对于设备厂商:针对割裂的生态,在产品设计时就要考虑未来所需对接的环境。比如,出海的智能产品往往需要做 Amazon 的 work with alexa (WWA)认证以及谷歌的 Work with Google Assistant (WWGA) 认证。如果是中高端产品,可能还需要考虑 Apple HomeKit 和其他第三方生态的认证。这无疑增加了产品开发的难度和周期,以及带来成本增加。
那么有什么办法能够让一台设备无缝工作在若干种不同生态下,并且能为用户提供统一的使用界面呢?于是,Matter 出现了。
1.2 它解决了什么问题
Matter 本质是由 CSA 联盟(连接标准联盟)制定的一个应用层面的标准,旨在打造一个统一的智能家居应用标准,以消除智能家居市场的碎片化。
而 CSA 联盟的前身,是2019 年,由亚马逊、苹果、谷歌、三星 SmartThings 和 Zigbee 联盟合作组建的 Project Connected Home over IP (CHIP)组织。当时组织推出了一个 CHIP 的开源项目,并经过一些时间的准备和发展之后,在 21 年正式命名为 Matter,并由 CSA 联盟运营和发展。再往前推,还会发现 CSA 联盟的前身就是 Zigbee 联盟。
用相对官方的话来表述,Matter 只是一个应用标准,它的传输是建立在支持 IPv6 的 TCP 和 UDP 协议上的,Matter 不对传输层进行约定,Matter 也不对网络进行约定,但是 Matter 约定了只能使用Thread、Wi-Fi 或Ethernet 三种连接协议。
通俗点给人的理解是,Matter 定义了一系列的设备模型和交互模型,举个例子来说,智能灯是标准设备类型之一,它定义了很多操作,例如:on/off cluster 可以完成开关灯动作,Level control cluster 可以完成调节亮度的动作。 Color control cluster 可以完成颜色调节的动作。对于设备来说,只要遵循了这些标准模型,那么在支持 Matter 协议的生态当中就可以被理解和使用,这就打破了传统私有协议带来的壁垒。
而现在,包括 Apple、三星、谷歌、亚马逊、小米等越来越多的品牌和厂商加入到该联盟当中。假以时日,对于消费者来说,只需选择自己喜欢的带有 Matter 标识的产品,就将能轻松构建互联的智能家居生态,构建自己的家庭自动化,而不用担心具体设备的品牌问题。
1.3 最近的动态
(1) 在今年的早些时候, 联盟发布了 Matter 1.3 版本,对以下方面做了一定的改进:
- 对水和能源管理设备的新支持,包括能源管理、电动汽车充电和水资源管理。
- 增加了新的家电类型,如微波炉、烤箱、灶具、抽油烟机和洗衣机、干衣机。
- 增强媒体设备和智能家居的管理功能。
- 增强用户体验。
- 改进开发和调试体验。
具体的规范内容可以参考以下网址:Matter 1.3 规范发布。
(2)苹果在 ios 18 开发者版本降低了对家庭中枢的限制。在上年尝试 ESP 方案时,想把设备添加到 iPhone Home 会提示需要先添加一个中枢设备,而现在使用最新的 IOS 18 系统则可以直接添加 Matter 设备。
二、实践背景
我们之前定义和开发的 Smart Deadbolt 产品现在已经接近尾声了。在过去,我们希望它能够支持 Alexa 和 WWGA 以实现对海外生态的兼容,而如今我们看到了 Matter,这或许是一个新的解决方案。
尤其是对于设备制造商来说,过去我们需要面向不同生态进行的 N 项认证,这增加了因为不同技术栈对开发人员的要求。在过去,可能需要工程师团队了解 Alexa Skill 开发,又要对苹果的 HomeKit 有一定的了解,这是有一些挑战的。同时,多项认证的费用也不容小觑。而随着 Matter 的出现,如今可以大大简化这些认证流程并压缩成本,同时还能为消费者提供更加友好的体验,何乐而不为。
2.1 关于 Bridge
自 1.0 版本以来,Matter Bridge 一直作为标准中的一个产品类别。它的任务是翻译 "外部" 的协议和技术,以便Matter 能够理解它们。这是智能家居标准成功的重要先决条件,因为并非每个已购买设备的人都想丢弃它们并用新的与 Matter 兼容的设备替换它们。
(1)官方对 bridge 的描述
非 Matter 设备作为桥接设备暴露给 Fabric 上的节点。Matter 节点既可以与(本地)Matter 设备通信,也可以与桥接设备通信(通过Matter bridge在 Matter 和其他协议之间进行转换)。
比如,利用 CHIP 的 ZAP 工具,构建一个 Matter 的 Bridge 设备:
(2)本次采用的方案:
我们知道,在去年 Yale Assure Lock 方案中,他们支持到了一颗可拔插的 Matter 模块以适配外部生态。从分析来看,这个模块也是起到了一个 Bridge 的功能,并通过串口和 Lock 设备进行通讯以响应外部指令。
这次实践参考了这种形式,但是由于 Lock 已经是成品设备,所以不在锁体上实现串口接入。而是通过蓝牙的形式同 Lock 的私有协议进行通讯,原理如下所示:
简单理解,实际上就是把 Bridge 映射成了一个虚拟的 Matter 设备,并通过私有协议和蓝牙将 Matter 指令转换成设备指令。
至于这里为什么会使用到两块 CCK (Nordic 开发板)以及具体的流程,在第三部分会进行解释。
2.2 开发平台
(1)软件环境:VSCODE + nRF Connect SDK,其中:
-
toolChains 版本为 v2.6.1。
-
nRF Connect SDK 版本为 v2.6.1。
-
关于这套 SDK 的安装方法,可以参考官方的一篇文档:开发 nRF Connect SDK(NCS)/Zephyr应用程序。
(2)开发板:
- 两块 Nordic CCK 开发板,CCK 板载有 nRF5340 和nRF7002 两颗芯片。其中,nRF7002/nRF7001 是 Wi-Fi 6 协同 IC,他们只运行 Wi-Fi 有关的 MAC 层,Matter 的其他部分还是跑在 nRF5340 上。
(3)生态应用及配件:
-
Alexa Echo 4 日版。
-
Samsung 海外版手机。
-
Alexa App。
三、过程记录
3.1 配置开发环境
(1)首先本地已经安装了 Microsoft Visual Studio Code,然后打开它进入 “扩展” 搜索 “nRF Connect for VS Code Extension Pack” 进行安装。该项拓展安装时,其它所需的 nRF 插件也会被自动安装。
(2)然后点击插件图标,进入后看到 Manage SDKs,选择安装 nRF Connect SDK。目前最新的版本是 2.6.1,默认选择最新的版本。这里值得注意的是, SDK 被官方放到了 Github 的服务器上,所以需要一些科学的方法,否则容易发生下载失败的情况。
(3)接下来安装 Toolchain,也可以直接通过 Vscode 进行安装。根据刚才选择的 nRF Connect SDK 版本选择对应版本的 Toolchain,这里安装的也是 2.6.1 版本。
(4)继续安装必须的 Python 脚本,nRF Connect SDK 虽然已经预装了大部分的 Python 脚本,但是 Matter 模块里面有些Python脚本还没有安装。为了防止我们电脑本地的 Python 环境对安装造成干扰,这里推荐使用 VS code 终端来执行命令,这样就保证了该命令行的环境是 nRF Connect SDK Toolchain 设置的环境。命令参考如下:
pip3 install -r C:/ncs/v2.6.1/modules/lib/matter/scripts/setup/requirements.nrfconnect.txt
这样系统就会自动补全nRF Connect SDK Toolchain 缺少的 Python 包。
(5)按照官方指引,最后安装一个 ZAP 工具。进入 modules\lib\matter 的仓库主目录中,然后执行以下指令,并将安装的根目录添加到操作系统变量中。
python scripts/setup/nrfconnect/get_zap.py -l C:\Nordic\Tools\zap-win-x64 -o
3.2 开发私有蓝牙协议
新建一个项目,参考官方蓝牙的 central 例程编写一个简单的业务程序。即指定一个目标 Lock 的蓝牙地址,并尝试与其建立蓝牙连接。连接建立后根据安全协议向其传递认证信息,并通过 nodify 获得 Lock 的返回。如果认证通过,则连接将持续保持并等待接收蓝牙指令。否则,认证失败,蓝牙连接将被释放。
(1)给定一个我们目标设备的蓝牙 MAC:
D8:5F:77:26:1A:0A
(2)当程序开始运行时,打开蓝牙并开启扫描:
static void start_scan(void)
{
int err ;
bool ble_status = bt_is_ready;
printk("ble status is %s\n", ble_status ? "true" : "false");
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_ACTIVE,
.options = BT_LE_SCAN_OPT_NONE,
.interval = BT_GAP_SCAN_FAST_INTERVAL,
.window = BT_GAP_SCAN_FAST_WINDOW,
};
err = bt_le_scan_start(&scan_param, device_found);
if (err) {
printk("Scanning failed to start (err %0d)\n", err);
return;
}
printk("Scanning successfully started\n");
}
(3)然后,通过设备发现过滤掉那些离我们过远的蓝牙设备并从中筛选出目标设备,并尝试建立蓝牙连接。
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
struct net_buf_simple *ad)
{
char addr_str[BT_ADDR_LE_STR_LEN];
int err ;
if (default_conn) {
return;
}
if (type != BT_GAP_ADV_TYPE_ADV_IND &&
type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
return;
}
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
if (addr -> type != BT_ADDR_LE_PUBLIC){
return ;
}
/* filter the target bluetooth address */
if (!strstr(addr_str, lock_ble_mac)){
return ;
}
printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
/* connect only to devices in close proximity */
if (rssi < -70) {
return;
}
if (bt_le_scan_stop()) {
return;
}
struct bt_conn_le_create_param create_param = {
.options = BT_CONN_LE_OPT_NONE,
.interval = BT_GAP_SCAN_FAST_INTERVAL,
.window = BT_GAP_SCAN_FAST_WINDOW
};
struct bt_le_conn_param conn_param = {
.interval_min = BT_GAP_INIT_CONN_INT_MIN,
.interval_max = BT_GAP_INIT_CONN_INT_MAX,
.latency = 0,
.timeout = 400
};
err = bt_conn_le_create(addr, &create_param,
&conn_param, &default_conn);
if (err) {
printk("Create conn to %s failed (%d)\n", addr_str, err);
start_scan();
}
}
(4)如果连接没有建立成功,则会重新开始扫描并重试连接。如果能够和目标设备建立蓝牙连接,则进入到服务发现过程。根据安全协议,在这个步骤中我们会对指定的 Service 和 Characteristic 进行一系列认证动作。在认证完成后,连接进入稳定状态,并等待接收下一步指令。同时定义两个方法,实现对指定 Lock 的锁定 / 解锁操作。由于这部分涉及产品的安全和内部协议,所以不做过多的细节表述。
(5)最后,定义两个函数用以调用 lock 和 unlock 线程:
void unlock_thread_func(void){
k_thread_create(&unlock_thread, unlock_stack_area, sizeof(unlock_stack_area),
unlock_func, NULL,NULL,NULL,5,0,K_NO_WAIT);
k_thread_start(&unlock_thread);
return;
}
void lock_thread_func(void){
k_thread_create(&lock_thread, lock_stack_area, sizeof(lock_stack_area),
lock_func, NULL,NULL,NULL,5,0,K_NO_WAIT);
k_thread_start(&lock_thread);
return;
}
3.3 创建两块 CCK 开发板间的串口通信
问:为什么要用两块开发板?
答:因为我们在官方 DEMO 中编写我们自己的私有蓝牙业务时,Zephyr 会提示蓝牙冲突问题。由于想要快速验证且不想修改过多的 Matter 代码,加上咱产品人员毕竟不是专业的嵌入式开发,对于 RTOS 的掌握不够熟练,所以干脆通过串口的形式让两块开发板各司其职,算是绕过了这个问题。但在后续正式方案中,使用一颗性能足够,且支持 Matter 的 Wi-Fi 和 BLE 的多协议 MCU / SOC 应该就可以解决问题。
3.4 修改并烧录官方的 Lock Demo。
(1) 修改 prj.conf,加入对串口的支持。
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=n
CONFIG_RTT_CONSOLE=y
CONFIG_UART_ASYNC_API=y
(2)在 zcl_callback 文件中,加入自定义的串口业务,以在 Lock 状态变更时通知给另一块 CCK。
(3)执行编译-烧录动作。
3.5 开发注意事项
在开发 Matter 的时候,使用的是 C++ 代码,而在开发蓝牙业务的时候,使用的是 C 代码,这就意味着一个工程中可能会同时存在这两种语言,这也是 Matter 应用非常突出的特性,因而也算是一份比较复杂且富有挑战的工作。
四. 效果演示
这里主要是尝试亚马逊对 Matter 接入的支持能力,打开 Amazon Alexa 官方应用,注册账号后,右上角选择添加设备。在 Shortcuts 区域可以看到,有一个 Matter 的标识:
点进去之后,输入充当 Matter 虚拟 Lock 的那块 CCK 的 Matter Numeric Code,并打开手机蓝牙(这里事先要先把 Alexa Echo 4 音响绑定到账户里,并且保证配置完成可以正常使用)。然后 App 就会尝试和 Matter 设备建立通讯并传递校验信息。
这个过程会比较漫长,需要耐心等待,并根据 Alexa App 的提示进行操作。如果配置完成,你可以在 Home 页面看到刚刚添加好的 Lock 设备。