<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Oniums</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://onium.top/</id>
  <link href="https://onium.top/" rel="alternate"/>
  <link href="https://onium.top/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Oniums</rights>
  <subtitle>个人博客</subtitle>
  <title>Oniums</title>
  <updated>2026-08-02T16:07:55.768Z</updated>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="搭建教程" scheme="https://onium.top/categories/%E6%90%AD%E5%BB%BA%E6%95%99%E7%A8%8B/"/>
    <category term="Telink" scheme="https://onium.top/tags/telink/"/>
    <category term="Zephyr" scheme="https://onium.top/tags/zephyr/"/>
    <category term="Matter" scheme="https://onium.top/tags/matter/"/>
    <category term="固件构建" scheme="https://onium.top/tags/%E5%9B%BA%E4%BB%B6%E6%9E%84%E5%BB%BA/"/>
    <category term="CMake" scheme="https://onium.top/tags/cmake/"/>
    <category term="west" scheme="https://onium.top/tags/west/"/>
    <content>
      <![CDATA[<p>第一次接触 Telink Matter SDK 时，很容易产生一个疑问：Zephyr 在一个仓库，Matter 在另一个仓库，底下还有 HAL、OpenThread 和一些静态库，执行一次 <code>west build</code> 后，它们怎么就变成了一个固件？</p><p>先记住最重要的结论：</p><blockquote><p><strong>通常不是先生成一个 Zephyr 固件和一个 Matter 固件，再把两个 BIN 拼起来。Matter、Zephyr、应用和芯片底层会先分别编译成许多目标文件或静态库，最后由链接器装进同一个 <code>zephyr.elf</code>，再转换成 <code>zephyr.bin</code>。</strong></p></blockquote><span id="more"></span><p>如果启用了 MCUboot、签名或出厂数据，后面还会有一次镜像签名或按 Flash 地址合并。那属于“固件打包”，不是把 Zephyr 和 Matter 两套程序硬拼在一起。</p><p>本文以公开的 Telink、Zephyr 和 Matter 仓库为线索，不要求读者先懂 CMake、Kconfig 或链接器。读完后，你应该能回答：</p><ol><li>每个仓库分别负责什么？</li><li><code>west build</code> 到底调用了谁？</li><li>Zephyr 在哪里进入 Telink 的底层 API？</li><li><code>zephyr.elf</code>、<code>zephyr.bin</code> 和 <code>merged.bin</code> 有什么区别？</li></ol><h2 id="先认识几位参与者"><a href="#先认识几位参与者" class="headerlink" title="先认识几位参与者"></a>先认识几位参与者</h2><p>可以把一次固件构建想成盖房子：</p><table><thead><tr><th>组成部分</th><th>主要职责</th><th>类比</th></tr></thead><tbody><tr><td>产品应用</td><td>按键、传感器、状态机和产品逻辑</td><td>房屋的使用需求</td></tr><tr><td>Matter</td><td>配网、设备模型、Cluster 和安全通信</td><td>智能家居的通用规则</td></tr><tr><td>Zephyr</td><td>线程、定时器、内存、日志、驱动框架和构建系统</td><td>施工组织与基础设施</td></tr><tr><td>OpenThread</td><td>Thread 网络协议</td><td>通往外界的道路系统</td></tr><tr><td>Telink 驱动与 HAL</td><td>把通用接口落到具体芯片外设和射频</td><td>真正操作机器的工人</td></tr><tr><td>工具链</td><td>编译、链接并转换文件格式</td><td>加工与装配设备</td></tr></tbody></table><p>这些部分不是彼此独立运行的几个固件。它们更像不同来源的零件，最后被装进同一个可执行程序。</p><p>下面的仓库与文件关系核对时间为 2026 年 8 月 2 日。公开开发环境里，常见结构可以简化为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Zephyr workspace</span><br><span class="line">├── zephyr/                       # RTOS、驱动框架、west manifest</span><br><span class="line">├── modules/hal/telink/           # Telink HAL、适配层和底层依赖</span><br><span class="line">├── modules/lib/openthread/       # OpenThread</span><br><span class="line">├── modules/lib/openthread_telink_lib/  # 某些配置使用的 Telink OpenThread 库</span><br><span class="line">└── matter/                       # connectedhomeip，Matter SDK 与示例应用</span><br></pre></td></tr></table></figure><p>实际目录名会随 SDK 版本变化，但角色基本不变。<code>west.yml</code> 像一张依赖清单：它记录要取哪些仓库、放在哪个目录、固定到哪个 revision。Telink 官方环境准备流程中的 <code>west update</code> 和 <code>west blobs fetch hal_telink</code>，就是根据工作区描述取回源码模块和 HAL 所需内容。</p><h2 id="从一条命令开始"><a href="#从一条命令开始" class="headerlink" title="从一条命令开始"></a>从一条命令开始</h2><p>Telink 的公开 Matter 示例通常从类似命令开始：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> scripts/activate.sh</span><br><span class="line">west build -b &lt;board&gt; -- -DFLASH_SIZE=&lt;size&gt;</span><br></pre></td></tr></table></figure><p>表面上只运行了 <code>west</code>，背后大致会经过这条链：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">west build</span><br><span class="line">  ↓</span><br><span class="line">CMake 配置应用和 Zephyr</span><br><span class="line">  ├── 读取 CMakeLists.txt</span><br><span class="line">  ├── 合并 prj.conf / Kconfig</span><br><span class="line">  ├── 解析 board 与 Devicetree overlay</span><br><span class="line">  └── 生成 Ninja 构建规则</span><br><span class="line">  ↓</span><br><span class="line">GN + Ninja 编译 Matter 库</span><br><span class="line">  ↓</span><br><span class="line">Ninja 编译应用、Zephyr、OpenThread、驱动和 HAL</span><br><span class="line">  ↓</span><br><span class="line">链接为 build/zephyr/zephyr.elf</span><br><span class="line">  ↓</span><br><span class="line">objcopy 转换为 build/zephyr/zephyr.bin</span><br><span class="line">  ↓</span><br><span class="line">按配置执行签名、OTA 或多镜像合并</span><br></pre></td></tr></table></figure><p>下面逐步拆开看。</p><h2 id="第一步：应用把构建入口交给-Zephyr"><a href="#第一步：应用把构建入口交给-Zephyr" class="headerlink" title="第一步：应用把构建入口交给 Zephyr"></a>第一步：应用把构建入口交给 Zephyr</h2><p>以公开的 Matter Telink 示例为例，应用目录里通常能看到：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">telink/</span><br><span class="line">├── CMakeLists.txt</span><br><span class="line">├── prj.conf</span><br><span class="line">├── boards/</span><br><span class="line">├── src/</span><br><span class="line">└── *.zap 或其他数据模型文件</span><br></pre></td></tr></table></figure><p>这些文件分别回答不同问题：</p><ul><li><code>CMakeLists.txt</code>：哪些源码要参与编译，还要加载哪些构建模块；</li><li><code>prj.conf</code>：要打开哪些 Zephyr、Matter、网络和驱动功能；</li><li>board 与 overlay：芯片、内存、GPIO、UART、Flash 分区等硬件描述；</li><li>ZAP 或数据模型文件：Matter Endpoint、Cluster、Attribute 和 Command；</li><li><code>src/</code>：应用自己的 C&#x2F;C++ 代码。</li></ul><p>Matter 示例的 Telink <code>common.cmake</code> 会整理配置和 overlay，然后把 <code>config/telink/chip-module</code> 加入 <code>ZEPHYR_EXTRA_MODULES</code>，最后调用 <code>find_package(Zephyr ...)</code>。这一步可以简单理解为：</p><blockquote><p>“这是一个 Matter 应用，但请使用 Zephyr 的规则来组织整次构建。”</p></blockquote><h2 id="第二步：Kconfig-和-Devicetree-决定“编什么”和“硬件在哪”"><a href="#第二步：Kconfig-和-Devicetree-决定“编什么”和“硬件在哪”" class="headerlink" title="第二步：Kconfig 和 Devicetree 决定“编什么”和“硬件在哪”"></a>第二步：Kconfig 和 Devicetree 决定“编什么”和“硬件在哪”</h2><p>初学者经常把 <code>prj.conf</code> 和 Devicetree 混在一起，可以先这样区分：</p><ul><li><strong>Kconfig &#x2F; <code>prj.conf</code> 决定要不要某个功能。</strong> 例如是否启用 Bluetooth、OpenThread、日志或 MCUboot。</li><li><strong>Devicetree 决定硬件是什么、地址在哪、引脚怎样接。</strong> 例如某个 UART、GPIO 或 Flash 分区的位置。</li></ul><p>CMake 配置阶段会把这些输入转换成后续编译能使用的结果，例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">build/zephyr/.config          # 最终生效的 Kconfig</span><br><span class="line">build/zephyr/zephyr.dts       # 最终合并后的硬件描述</span><br><span class="line">build/zephyr/include/generated/...  # 生成的配置头文件</span><br></pre></td></tr></table></figure><p>所以，改了 <code>prj.conf</code> 或 overlay 后，变化并不是运行时才被“读取”，而是在编译前就决定哪些代码存在、使用哪些地址和参数。</p><h2 id="第三步：Matter-为什么使用-GN，又怎样回到-Zephyr？"><a href="#第三步：Matter-为什么使用-GN，又怎样回到-Zephyr？" class="headerlink" title="第三步：Matter 为什么使用 GN，又怎样回到 Zephyr？"></a>第三步：Matter 为什么使用 GN，又怎样回到 Zephyr？</h2><p>Matter SDK 本身大量使用 GN + Ninja，Zephyr 则主要使用 CMake。Telink 没有要求初学者手工运行两套互不相干的构建，而是在 <code>config/telink/chip-module</code> 中搭了一座桥。</p><p>这座桥主要做三件事：</p><ol><li>把 Zephyr 的编译器、编译选项和 Kconfig 结果转换为 Matter GN 参数；</li><li>通过 CMake <code>ExternalProject</code> 调用 GN 和 Ninja 编译 Matter；</li><li>把生成的 Matter 静态库加入 Zephyr 最终链接。</li></ol><p>因此，中间过程虽然能看到 CMake、GN 和两次 Ninja，但最终目标仍然是同一个应用镜像：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Matter 源码</span><br><span class="line">  -&gt; GN 生成规则</span><br><span class="line">  -&gt; Matter 静态库 ───────────┐</span><br><span class="line">                              │</span><br><span class="line">应用源码 -&gt; 目标文件 ─────────┤</span><br><span class="line">Zephyr   -&gt; 内核与子系统库 ───┼─&gt; zephyr.elf</span><br><span class="line">OpenThread -&gt; 网络协议库 ──────┤</span><br><span class="line">Telink HAL -&gt; 驱动/底层库 ─────┘</span><br></pre></td></tr></table></figure><p>这里的“静态库”可以先理解成装有很多已编译零件的盒子。链接器会从盒子中取出当前程序真正引用的部分，并解析函数之间的调用关系。</p><h2 id="第四步：Zephyr-在哪里调用-Telink-底层？"><a href="#第四步：Zephyr-在哪里调用-Telink-底层？" class="headerlink" title="第四步：Zephyr 在哪里调用 Telink 底层？"></a>第四步：Zephyr 在哪里调用 Telink 底层？</h2><p>上层应用通常调用的是通用 API，例如 Flash、Bluetooth 或 IEEE 802.15.4 API。Zephyr 的 Telink 驱动负责把这些通用动作翻译成具体芯片函数。</p><p>最值得看的不是所有源码，而是下面三条代表性调用链。</p><h3 id="例一：读写-Flash"><a href="#例一：读写-Flash" class="headerlink" title="例一：读写 Flash"></a>例一：读写 Flash</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">应用 / Settings / 存储模块</span><br><span class="line">  ↓ Zephyr Flash API</span><br><span class="line">zephyr/drivers/flash/soc_flash_tlx.c</span><br><span class="line">  ↓</span><br><span class="line">flash_read_page()</span><br><span class="line">flash_write_page()</span><br><span class="line">flash_erase_sector()</span><br><span class="line">  ↓</span><br><span class="line">Telink HAL / 芯片 Flash 驱动</span><br></pre></td></tr></table></figure><p><code>soc_flash_tlx.c</code> 最后注册的是 Zephyr <code>flash_driver_api</code>，但函数内部已经在调用 Telink 的 <code>flash_*</code> API。也就是说，上层看到统一的 Zephyr 接口，底层执行的是 Telink 芯片操作。</p><h3 id="例二：BLE-Host-怎样进入-Telink-Controller"><a href="#例二：BLE-Host-怎样进入-Telink-Controller" class="headerlink" title="例二：BLE Host 怎样进入 Telink Controller"></a>例二：BLE Host 怎样进入 Telink Controller</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Matter commissioning / Zephyr Bluetooth Host</span><br><span class="line">  ↓ HCI 命令和数据</span><br><span class="line">zephyr/drivers/bluetooth/hci/hci_tlx.c</span><br><span class="line">  ↓</span><br><span class="line">tlx_bt_controller_init()</span><br><span class="line">tlx_bt_host_send_packet()</span><br><span class="line">  ↓</span><br><span class="line">Telink BLE Controller 与射频底层</span><br></pre></td></tr></table></figure><p>反方向收到 HCI Event 或 ACL 数据时，Telink 适配层会把数据送回 Zephyr 的 <code>bt_recv()</code>。所以这条链是双向的：Zephyr Host 向下发命令，Controller 向上交事件。</p><p>这也解释了一个常见现象：应用和 GATT 代码可能都在 Matter&#x2F;Zephyr 上层，但 BLE Controller 的核心实现未必位于同一个源码目录。</p><h3 id="例三：OpenThread-怎样使用-Telink-2-4-GHz-射频"><a href="#例三：OpenThread-怎样使用-Telink-2-4-GHz-射频" class="headerlink" title="例三：OpenThread 怎样使用 Telink 2.4 GHz 射频"></a>例三：OpenThread 怎样使用 Telink 2.4 GHz 射频</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Matter</span><br><span class="line">  ↓</span><br><span class="line">OpenThread</span><br><span class="line">  ↓ Zephyr IEEE 802.15.4 Radio API</span><br><span class="line">zephyr/drivers/ieee802154/ieee802154_tlx.c</span><br><span class="line">  ↓</span><br><span class="line">rf_set_chn()</span><br><span class="line">rf_set_rxmode()</span><br><span class="line">rf_set_txmode()</span><br><span class="line">rf_tx_pkt()</span><br><span class="line">  ↓</span><br><span class="line">Telink RF / DMA / IRQ 底层</span><br></pre></td></tr></table></figure><p>OpenThread 负责 Thread 协议，但它不会自己操作 Telink 的射频寄存器。Zephyr 的 IEEE 802.15.4 驱动实现标准 Radio API，再调用 Telink 的 RF、DMA、定时器和中断接口。</p><p>把三条链放在一起，就能看到稳定的分层：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">产品 / Matter / OpenThread</span><br><span class="line">        ↓ 通用接口</span><br><span class="line">Zephyr 子系统和 driver API</span><br><span class="line">        ↓ 芯片适配</span><br><span class="line">Telink Zephyr driver</span><br><span class="line">        ↓ 厂商 API</span><br><span class="line">Telink HAL、驱动源码或静态库</span><br><span class="line">        ↓</span><br><span class="line">芯片外设与射频</span><br></pre></td></tr></table></figure><h2 id="“底下还有个库”到底是哪一个？"><a href="#“底下还有个库”到底是哪一个？" class="headerlink" title="“底下还有个库”到底是哪一个？"></a>“底下还有个库”到底是哪一个？</h2><p>这个记忆很可能是对的，但要区分两类库。</p><h3 id="Telink-HAL-与-BLE-芯片底层库"><a href="#Telink-HAL-与-BLE-芯片底层库" class="headerlink" title="Telink HAL 与 BLE&#x2F;芯片底层库"></a>Telink HAL 与 BLE&#x2F;芯片底层库</h3><p>Zephyr 的 manifest 会把 <code>hal_telink</code> 放到 <code>modules/hal/telink</code>。较新的公开 HAL 结构中，<code>hal_v2</code> 还会获取 Telink 的公开 <code>tl_ble_sdk</code> 仓库，并针对目标 SoC 链接对应的静态库。</p><p>以 TL323X 为例，公开文件中可以看到两种容易遇到的命名：</p><ul><li>原始 SDK 的 <code>proj_lib/liblt_TL323X.a</code>；</li><li>Zephyr 集成流程中的 <code>lib_zephyr_tl323x.a</code>。</li></ul><p>具体名字和生成方式会随分支、SDK 发布版发生变化，不要只靠文件名判断版本。更可靠的方法是查看当前 <code>hal_telink</code> 的 <code>CMakeLists.txt</code>、实际链接命令和最终 map 文件。</p><p>同时也不要把 <code>.a</code> 理解成“整个底层只有一个黑盒”。公开 <code>tl_ble_sdk</code> 中还能看到 GPIO、Flash、UART、I2C 等驱动源码和头文件；某些协议栈、控制器或优化实现则可能以静态库参与链接。<strong>仓库可以公开下载，不等于其中每个库都有完整可读源码，也不自动代表所有内容使用同一种开源许可。</strong></p><h3 id="可选的-OpenThread-Telink-库"><a href="#可选的-OpenThread-Telink-库" class="headerlink" title="可选的 OpenThread Telink 库"></a>可选的 OpenThread Telink 库</h3><p><code>openthread_telink_lib</code> 是另一件东西。它公开提供 OpenThread 头文件以及类似下面的库：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">libopenthread-ftd-extended.a</span><br><span class="line">libopenthread-ftd-reduced.a</span><br></pre></td></tr></table></figure><p>只有相应 Kconfig 选项开启时，模块的 CMake 才会选择并链接它。它解决的是 OpenThread 库实现选择，不是 BLE Controller 库，也不等于 Telink 全部 HAL。</p><p>因此，当日志或 map 文件里看到一个 <code>.a</code>，先问三个问题：</p><ol><li>它是芯片驱动&#x2F;BLE Controller，还是 OpenThread？</li><li>是当前配置主动选择的，还是只存在于工作区但没有参与链接？</li><li>它有哪些公开头文件和源码，哪些实现只有二进制？</li></ol><h2 id="第五步：链接器怎样变出一个完整程序？"><a href="#第五步：链接器怎样变出一个完整程序？" class="headerlink" title="第五步：链接器怎样变出一个完整程序？"></a>第五步：链接器怎样变出一个完整程序？</h2><p>编译器通常一次只编译一个源码文件，产生许多 <code>.o</code> 目标文件；Matter、Zephyr、OpenThread 和 HAL 也可能先整理成多个 <code>.a</code> 静态库。</p><p>链接阶段会：</p><ul><li>找到 <code>main</code> 和系统启动入口；</li><li>解析一个函数对另一个函数的引用；</li><li>按 linker script 安排代码、只读数据、RAM 数据和保留区；</li><li>丢弃没有被使用的部分；</li><li>生成带符号和段信息的 <code>zephyr.elf</code>。</li></ul><p>所以“完整固件”的第一次成形发生在链接阶段，而不是最后复制 BIN 时。</p><p>想确认某个底层函数有没有真的进入固件，可以查看：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">build/zephyr/zephyr.map</span><br><span class="line">build/zephyr/zephyr.elf</span><br></pre></td></tr></table></figure><p>map 文件适合追踪“某个符号来自哪个 <code>.o</code> 或 <code>.a</code>”；ELF 则可以配合 <code>nm</code>、<code>readelf</code>、<code>objdump</code> 和调试器继续分析。</p><h2 id="第六步：ELF、BIN-和-merged-bin-有什么区别？"><a href="#第六步：ELF、BIN-和-merged-bin-有什么区别？" class="headerlink" title="第六步：ELF、BIN 和 merged.bin 有什么区别？"></a>第六步：ELF、BIN 和 merged.bin 有什么区别？</h2><p>常见产物可以这样理解：</p><table><thead><tr><th>文件</th><th>主要用途</th></tr></thead><tbody><tr><td><code>zephyr.elf</code></td><td>包含代码、数据、地址和调试符号，适合调试与分析</td></tr><tr><td><code>zephyr.bin</code></td><td>从 ELF 中提取出的原始二进制，常用于烧录</td></tr><tr><td><code>zephyr.map</code></td><td>记录内存布局、符号和来源，适合查大小与调用来源</td></tr><tr><td><code>merged.bin</code></td><td>Telink 后处理得到的最终入口文件；内容取决于配置</td></tr></tbody></table><p>公开的 Telink <code>process_binaries.py</code> 中，如果当前配置没有额外镜像需要合并，<code>merged.bin</code> 可以只是指向 <code>zephyr.bin</code> 的链接。启用不同功能后，它也可能负责：</p><ul><li>把 MCUboot 与签名后的应用放到各自 Flash offset；</li><li>合入出厂数据分区；</li><li>生成 OTA 或 DFU 需要的文件。</li></ul><p>因此，看到 <code>merged.bin</code> 不能立刻推断它一定包含多个镜像；看到只有一个 <code>zephyr.bin</code>，也不能推断它内部只有 Zephyr。Matter、OpenThread 和应用通常早已在 ELF 链接阶段进入其中。</p><h2 id="一个最实用的排查顺序"><a href="#一个最实用的排查顺序" class="headerlink" title="一个最实用的排查顺序"></a>一个最实用的排查顺序</h2><p>如果想亲手确认构建过程，不必一开始读遍所有仓库。按下面顺序就够了：</p><ol><li>看应用 <code>CMakeLists.txt</code>、<code>prj.conf</code> 和 board overlay，确认构建入口；</li><li>看 <code>build/zephyr/.config</code> 与 <code>zephyr.dts</code>，确认最终配置；</li><li>在构建日志或 <code>build.ninja</code> 中找 <code>chip-gn</code>，确认 Matter 子构建；</li><li>在 <code>zephyr.map</code> 中搜索目标函数或 <code>.a</code> 文件名，确认它是否进入最终 ELF；</li><li>看 <code>process_binaries.py</code> 的日志和输出，确认是否又做了签名或镜像合并。</li></ol><p>定位某个外设时，再沿着一条窄链向下追：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">应用调用</span><br><span class="line">  -&gt; Zephyr API</span><br><span class="line">  -&gt; Telink Zephyr driver</span><br><span class="line">  -&gt; Telink 头文件中的函数声明</span><br><span class="line">  -&gt; 对应 .c 或 .a</span><br><span class="line">  -&gt; 最终 map 文件中的来源</span><br></pre></td></tr></table></figure><p>这样比在所有仓库里搜索“Telink”更容易建立完整证据。</p><h2 id="初学者最容易混淆的六件事"><a href="#初学者最容易混淆的六件事" class="headerlink" title="初学者最容易混淆的六件事"></a>初学者最容易混淆的六件事</h2><h3 id="1-west-不是编译器"><a href="#1-west-不是编译器" class="headerlink" title="1. west 不是编译器"></a>1. <code>west</code> 不是编译器</h3><p>它主要管理工作区并调用构建系统。真正完成配置、编译和链接的是 CMake、GN、Ninja 与工具链。</p><h3 id="2-Matter-不是另一个独立-RTOS"><a href="#2-Matter-不是另一个独立-RTOS" class="headerlink" title="2. Matter 不是另一个独立 RTOS"></a>2. Matter 不是另一个独立 RTOS</h3><p>在这个平台组合里，Matter 使用 Zephyr 提供的线程、网络、存储、Bluetooth 和驱动能力。</p><h3 id="3-Matter-库不是第二个可单独运行的-BIN"><a href="#3-Matter-库不是第二个可单独运行的-BIN" class="headerlink" title="3. Matter 库不是第二个可单独运行的 BIN"></a>3. Matter 库不是第二个可单独运行的 BIN</h3><p>它通常作为库参与最终链接。只有多核或特殊架构才可能出现额外可执行镜像，不能把特殊情况当成普通流程。</p><h3 id="4-west-update-不等于所有东西都来自-Zephyr-官方仓库"><a href="#4-west-update-不等于所有东西都来自-Zephyr-官方仓库" class="headerlink" title="4. west update 不等于所有东西都来自 Zephyr 官方仓库"></a>4. <code>west update</code> 不等于所有东西都来自 Zephyr 官方仓库</h3><p>它会按照 manifest 拉取多个项目，其中可以包含 Telink fork、HAL 和其他模块。</p><h3 id="5-工作区里有某个库，不代表它进入了当前固件"><a href="#5-工作区里有某个库，不代表它进入了当前固件" class="headerlink" title="5. 工作区里有某个库，不代表它进入了当前固件"></a>5. 工作区里有某个库，不代表它进入了当前固件</h3><p>Kconfig、CMake 条件和链接器引用共同决定它是否参与构建。最终以配置、链接命令和 map 文件为准。</p><h3 id="6-编译成功不等于设备行为已经验证"><a href="#6-编译成功不等于设备行为已经验证" class="headerlink" title="6. 编译成功不等于设备行为已经验证"></a>6. 编译成功不等于设备行为已经验证</h3><p>编译和链接只能证明静态组合成立。启动、配网、BLE、Thread、Flash、低功耗和 OTA 仍需要真机日志、抓包或功耗测量。</p><h2 id="最后用一句话串起来"><a href="#最后用一句话串起来" class="headerlink" title="最后用一句话串起来"></a>最后用一句话串起来</h2><p>一次普通的 Telink Matter 构建，可以浓缩成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">west 找齐工作区</span><br><span class="line">  -&gt; CMake 组织 Zephyr 应用</span><br><span class="line">  -&gt; Kconfig 和 Devicetree 确定配置</span><br><span class="line">  -&gt; GN/Ninja 编译 Matter</span><br><span class="line">  -&gt; Ninja 编译其余模块</span><br><span class="line">  -&gt; 链接器把应用、Matter、Zephyr、OpenThread 和 Telink 底层装进 zephyr.elf</span><br><span class="line">  -&gt; 转成 zephyr.bin</span><br><span class="line">  -&gt; 需要时再签名或合并为最终镜像</span><br></pre></td></tr></table></figure><p>以后再面对庞大的 SDK，不需要先记住每个目录。先抓住“谁提供通用接口、谁做芯片适配、谁在最终链接中出现”这三件事，整个构建链就不会再像一个黑盒。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://doc.telink-semi.cn/doc/en/software/res/sdk/matter/telink_matter_developer_guide_en/">Telink Matter Developer Guide</a></li><li><a href="https://docs.zephyrproject.org/latest/develop/application/index.html">Zephyr：Application Development</a></li><li><a href="https://docs.zephyrproject.org/latest/build/cmake/index.html">Zephyr：Build System</a></li><li><a href="https://docs.zephyrproject.org/latest/develop/modules.html">Zephyr：Modules</a></li><li><a href="https://github.com/project-chip/connectedhomeip">Matter SDK：connectedhomeip</a></li><li><a href="https://github.com/project-chip/connectedhomeip/blob/master/config/telink/chip-module/CMakeLists.txt">Matter Telink 构建桥接模块：CMakeLists.txt</a></li><li><a href="https://github.com/project-chip/connectedhomeip/tree/master/src/platform/telink">Matter Telink 平台实现</a></li><li><a href="https://github.com/project-chip/connectedhomeip/blob/master/scripts/tools/telink/process_binaries.py">Matter Telink 镜像后处理：process_binaries.py</a></li><li><a href="https://github.com/telink-semi/zephyr">Telink Zephyr Fork</a></li><li><a href="https://github.com/telink-semi/zephyr/blob/develop_v3.3/drivers/flash/soc_flash_tlx.c">Telink Zephyr Flash Driver</a></li><li><a href="https://github.com/telink-semi/zephyr/blob/develop_v3.3/drivers/bluetooth/hci/hci_tlx.c">Telink Zephyr Bluetooth HCI Driver</a></li><li><a href="https://github.com/telink-semi/zephyr/blob/develop_v3.3/drivers/ieee802154/ieee802154_tlx.c">Telink Zephyr IEEE 802.15.4 Driver</a></li><li><a href="https://github.com/telink-semi/hal_telink">Telink HAL</a></li><li><a href="https://github.com/telink-semi/tl_ble_sdk">Telink BLE SDK</a></li><li><a href="https://github.com/telink-semi/openthread_telink_lib">Telink OpenThread Library</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/telink-zephyr-matter-build-pipeline/</id>
    <link href="https://onium.top/posts/telink-zephyr-matter-build-pipeline/"/>
    <published>2026-08-02T15:55:00.000Z</published>
    <summary>
      <![CDATA[<p>第一次接触 Telink Matter SDK 时，很容易产生一个疑问：Zephyr 在一个仓库，Matter 在另一个仓库，底下还有 HAL、OpenThread 和一些静态库，执行一次 <code>west build</code> 后，它们怎么就变成了一个固件？</p>
<p>先记住最重要的结论：</p>
<blockquote>
<p><strong>通常不是先生成一个 Zephyr 固件和一个 Matter 固件，再把两个 BIN 拼起来。Matter、Zephyr、应用和芯片底层会先分别编译成许多目标文件或静态库，最后由链接器装进同一个 <code>zephyr.elf</code>，再转换成 <code>zephyr.bin</code>。</strong></p>
</blockquote>]]>
    </summary>
    <title>Telink Matter SDK 入门：Zephyr、Matter 与底层库怎样组成一个固件？</title>
    <updated>2026-08-02T16:07:55.768Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Bluetooth LE" scheme="https://onium.top/tags/bluetooth-le/"/>
    <category term="BLE" scheme="https://onium.top/tags/ble/"/>
    <category term="GATT" scheme="https://onium.top/tags/gatt/"/>
    <category term="ATT" scheme="https://onium.top/tags/att/"/>
    <category term="入门" scheme="https://onium.top/tags/%E5%85%A5%E9%97%A8/"/>
    <content>
      <![CDATA[<p>打开一个蓝牙调试工具，点下 Connect，页面很快显示“Connected”。这是不是说明手机已经能读到设备数据，也能正常控制设备了？</p><p>不一定。</p><p><strong>BLE 连接成功，只表示两台设备已经建立了一条无线链路。</strong> 后面通常还要发现 Service、找到 Characteristic、确认读写方式、订阅通知，应用数据才真正开始流动。</p><span id="more"></span><p>本文不从复杂的协议分层开始，而是跟着一台简单的 BLE 温度计，看清手机从“发现设备”到“收到温度变化”之间发生了什么。</p><p>读完后，你应该能够回答三个问题：</p><ol><li>Service、Characteristic 和 Descriptor 分别是什么？</li><li>BLE 显示 Connected 后，手机为什么还要继续发现和订阅？</li><li>怎样判断问题卡在连接、GATT，还是设备自己的业务协议？</li></ol><h2 id="先看结论：一次常见的-BLE-通信过程"><a href="#先看结论：一次常见的-BLE-通信过程" class="headerlink" title="先看结论：一次常见的 BLE 通信过程"></a>先看结论：一次常见的 BLE 通信过程</h2><p>先不管每个名词的精确定义，只看一条最常见的时间线：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">温度计发送广播</span><br><span class="line">  ↓</span><br><span class="line">手机扫描并发现温度计</span><br><span class="line">  ↓</span><br><span class="line">手机发起连接</span><br><span class="line">  ↓</span><br><span class="line">BLE 链路建立：Connected</span><br><span class="line">  ↓</span><br><span class="line">双方可能进行配对、加密和 MTU 交换</span><br><span class="line">  ↓</span><br><span class="line">手机发现设备提供的 Service</span><br><span class="line">  ↓</span><br><span class="line">手机发现 Service 里的 Characteristic 和 Descriptor</span><br><span class="line">  ↓</span><br><span class="line">手机读取数据、写入命令，或者订阅通知</span><br><span class="line">  ↓</span><br><span class="line">温度变化时，设备主动向手机发送新值</span><br></pre></td></tr></table></figure><p>这里最容易混淆的是中间那条线：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">建立 BLE 连接 ≠ 已经找到 GATT 服务 ≠ 已经订阅数据 ≠ 业务功能正常</span><br></pre></td></tr></table></figure><p>每一步成功，都只能证明这一小步已经完成。</p><h2 id="连接前：广播和扫描是在做什么？"><a href="#连接前：广播和扫描是在做什么？" class="headerlink" title="连接前：广播和扫描是在做什么？"></a>连接前：广播和扫描是在做什么？</h2><p>BLE 设备在没有连接时，可以周期性发送很短的广播数据。广播通常可能包含：</p><ul><li>设备名称；</li><li>设备地址或身份相关信息；</li><li>某些重要 Service 的 UUID；</li><li>厂商自定义数据；</li><li>设备是否允许连接等信息。</li></ul><p>温度计不断发送广播，就像它在说：</p><blockquote><p>“我在这里，我叫客厅温度计，现在可以连接。”</p></blockquote><p>手机进行扫描，是在附近收听这些广播。收到广播，只证明手机“看见”了设备，并不代表双方已经连接。</p><p>当手机决定连接时，它会向目标设备发起连接请求。连接建立后，双方按照约定的时间间隔交换无线数据。此时调试工具通常会显示 Connected。</p><h3 id="三组角色不要混在一起"><a href="#三组角色不要混在一起" class="headerlink" title="三组角色不要混在一起"></a>三组角色不要混在一起</h3><p>BLE 中会遇到几组看起来相似的角色：</p><table><thead><tr><th>所处阶段</th><th>角色</th><th>简单理解</th></tr></thead><tbody><tr><td>广播阶段</td><td>Advertiser &#x2F; Scanner</td><td>一个发送广播，一个扫描广播</td></tr><tr><td>连接阶段</td><td>Peripheral &#x2F; Central</td><td>一个接受连接，一个发起连接</td></tr><tr><td>GATT 阶段</td><td>Server &#x2F; Client</td><td>一个提供数据，一个访问数据</td></tr></tbody></table><p>在常见的手机连接传感器场景中：</p><ul><li>手机通常是 Central，也是 GATT Client；</li><li>传感器通常是 Peripheral，也是 GATT Server。</li></ul><p>但这只是常见组合，不是强制绑定。Central 不一定永远是 GATT Client，Peripheral 也不一定永远是 GATT Server。</p><h2 id="连接后：GATT-像一组整理好的资料柜"><a href="#连接后：GATT-像一组整理好的资料柜" class="headerlink" title="连接后：GATT 像一组整理好的资料柜"></a>连接后：GATT 像一组整理好的资料柜</h2><p>连接只解决“怎样把数据送到对方”。设备究竟提供哪些数据、哪些可以读取、哪些可以写入，则主要由 GATT 描述。</p><p>可以把一台 GATT Server 想成一个资料柜：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">GATT Server</span><br><span class="line">├── Service：电池</span><br><span class="line">│   └── Characteristic：当前电量</span><br><span class="line">├── Service：设备信息</span><br><span class="line">│   ├── Characteristic：厂商名称</span><br><span class="line">│   └── Characteristic：固件版本</span><br><span class="line">└── Service：温度计功能</span><br><span class="line">    ├── Characteristic：当前温度</span><br><span class="line">    └── Characteristic：测量间隔</span><br></pre></td></tr></table></figure><p>Service、Characteristic 和 Descriptor，就是整理这个资料柜的三种基本结构。</p><h3 id="Service：一组相关功能"><a href="#Service：一组相关功能" class="headerlink" title="Service：一组相关功能"></a>Service：一组相关功能</h3><p>Service 用来把同一类功能放在一起，可以先把它理解成一个文件夹。</p><p>常见的标准 Service 有：</p><table><thead><tr><th>Service</th><th>用途</th></tr></thead><tbody><tr><td>Generic Access</td><td>设备名称、外观等基础访问数据</td></tr><tr><td>Generic Attribute</td><td>GATT 数据库自身发生变化时的相关能力</td></tr><tr><td>Device Information</td><td>厂商、型号、序列号、固件版本等设备信息</td></tr><tr><td>Battery Service</td><td>电池电量和电池状态</td></tr></tbody></table><p>设备也可以定义自己的 Service。例如，一台温度计可以使用自定义 Service 表达测量结果和设置项。</p><h3 id="Characteristic：真正要读写的数据项"><a href="#Characteristic：真正要读写的数据项" class="headerlink" title="Characteristic：真正要读写的数据项"></a>Characteristic：真正要读写的数据项</h3><p>Characteristic 是 Service 中具体的数据项。它通常包含：</p><ul><li>UUID：这是什么类型的数据；</li><li>Value：当前数据值；</li><li>Properties：允许怎样操作，例如 Read、Write、Notify；</li><li>Descriptor：对这个数据项的补充说明或配置。</li></ul><p>Properties 回答“支持什么操作”，Permissions 则回答“满足什么安全条件才允许操作”。所以，一个 Characteristic 即使带有 Read 属性，也可能要求链路先加密才能读取。</p><p>例如，标准 Battery Service 的 UUID 是 <code>0x180F</code>，其中 Battery Level Characteristic 的 UUID 是 <code>0x2A19</code>。如果它当前的 Value 是十进制 <code>83</code>，就表示剩余电量为 83%。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Battery Service（0x180F）</span><br><span class="line">└── Battery Level Characteristic（0x2A19）</span><br><span class="line">    ├── Value：83</span><br><span class="line">    ├── Properties：Read、Notify</span><br><span class="line">    └── Descriptor：通知开关</span><br></pre></td></tr></table></figure><p>标准功能通常使用 Bluetooth SIG 分配的 UUID。产品自己的功能则常使用 128-bit 自定义 UUID。</p><h3 id="Descriptor：Characteristic-的补充信息和开关"><a href="#Descriptor：Characteristic-的补充信息和开关" class="headerlink" title="Descriptor：Characteristic 的补充信息和开关"></a>Descriptor：Characteristic 的补充信息和开关</h3><p>Descriptor 属于某个 Characteristic，可以描述数据格式，也可以控制它的行为。</p><p>初学者最常见的是 Client Characteristic Configuration Descriptor，通常简称 <strong>CCCD</strong>，UUID 为 <code>0x2902</code>。</p><p>如果一个 Characteristic 支持 Notify 或 Indicate，Client 通常要先写入 CCCD，告诉 Server：</p><blockquote><p>“这个数据变化时，请主动发给我。”</p></blockquote><p>因此，看见 Characteristic 支持 Notify，不等于手机已经能收到通知。<strong>支持通知是一种能力，写入 CCCD 才是实际订阅。</strong></p><h2 id="UUID-和-Handle-有什么区别？"><a href="#UUID-和-Handle-有什么区别？" class="headerlink" title="UUID 和 Handle 有什么区别？"></a>UUID 和 Handle 有什么区别？</h2><p>调试工具里经常同时显示 UUID 和 Handle，它们不是一回事。</p><table><thead><tr><th>名称</th><th>用途</th><th>类比</th></tr></thead><tbody><tr><td>UUID</td><td>说明这个 Attribute 是什么类型</td><td>资料名称</td></tr><tr><td>Handle</td><td>指向当前 GATT 数据库中的具体条目</td><td>资料柜里的编号</td></tr></tbody></table><p>同一种标准 Characteristic 在不同设备上可以使用相同 UUID，但它在各自数据库里的 Handle 不一定相同。</p><p>应用通常先通过 UUID 发现目标，再使用发现到的 Handle 访问它。不要因为某次连接中 Handle 是 <code>0x0012</code>，就假设所有设备和所有固件版本都永远相同。</p><h2 id="Read、Write、Notify-和-Indicate"><a href="#Read、Write、Notify-和-Indicate" class="headerlink" title="Read、Write、Notify 和 Indicate"></a>Read、Write、Notify 和 Indicate</h2><p>找到 Characteristic 后，双方常用下面几种方式交换数据：</p><table><thead><tr><th>操作</th><th>谁先发起</th><th>简单理解</th></tr></thead><tbody><tr><td>Read</td><td>Client</td><td>“把现在的值告诉我”</td></tr><tr><td>Write</td><td>Client</td><td>“请把这个值改成我发送的内容”，并等待 GATT 层响应</td></tr><tr><td>Write Without Response</td><td>Client</td><td>“快速写入这个内容”，不等待对应的 GATT 写响应</td></tr><tr><td>Notify</td><td>Server</td><td>“数据变了，我主动告诉你”，不要求 ATT 层确认</td></tr><tr><td>Indicate</td><td>Server</td><td>“数据变了，我主动告诉你”，要求 Client 在 ATT 层确认</td></tr></tbody></table><p>假设温度计每次变化都要上报：</p><ol><li>手机发现温度 Characteristic；</li><li>手机写入它的 CCCD，开启 Notify；</li><li>温度从 24.1°C 变为 24.3°C；</li><li>设备发送 Notification；</li><li>手机收到新值并更新页面。</li></ol><p>如果第 2 步没有完成，设备即使一直在测温，手机也可能什么都收不到。</p><p>Notify 没有 ATT 层的逐条确认，Indicate 则有。这里说的是 GATT&#x2F;ATT 这一层，不表示底层无线链路完全没有校验或重传。</p><h2 id="ATT-又是什么？它和-GATT-有什么关系？"><a href="#ATT-又是什么？它和-GATT-有什么关系？" class="headerlink" title="ATT 又是什么？它和 GATT 有什么关系？"></a>ATT 又是什么？它和 GATT 有什么关系？</h2><p>可以先记住一句话：</p><blockquote><p>GATT 负责把数据组织成 Service、Characteristic 和 Descriptor；ATT 负责发现、读取、写入和传送这些 Attribute。</p></blockquote><p>如果 GATT 像餐厅菜单，ATT 就像点单和上菜时使用的规则：</p><ul><li>菜单怎样分组、一道菜叫什么，由 GATT 描述；</li><li>“读取这个值”“写入那个值”“这个值变化了”等消息怎样发送，由 ATT 处理。</li></ul><p>开发时经常直接使用平台提供的 GATT API，不需要手工拼每一个 ATT 数据包。但抓包、看日志或定位超时时，ATT Read、Write、Notification、MTU Exchange 等名字就会出现。</p><h2 id="MTU：一次-ATT-消息能装多少"><a href="#MTU：一次-ATT-消息能装多少" class="headerlink" title="MTU：一次 ATT 消息能装多少"></a>MTU：一次 ATT 消息能装多少</h2><p>MTU 可以先理解成“一次允许携带多大的包裹”。BLE 的默认 ATT MTU 是 23 字节，但这 23 字节还包含 ATT 自己的字段，并不全是应用数据。</p><p>连接后，Client 和 Server 可以交换各自支持的 MTU，最终使用双方都能接受的大小。更大的 MTU 通常能让较长数据减少拆分，但需要注意：</p><ul><li>MTU 交换成功，不代表 Service 已经发现；</li><li>MTU 更大，不代表通知已经订阅；</li><li>MTU 更大，也不保证业务一定更快；</li><li>真正能放入的 Characteristic Value 通常小于 ATT MTU。</li></ul><p>初学阶段不用急着计算每一层开销。先把 MTU 当成连接建立后可能进行的一项“传输能力协商”即可。</p><h2 id="配对、绑定和加密是不是每次都有？"><a href="#配对、绑定和加密是不是每次都有？" class="headerlink" title="配对、绑定和加密是不是每次都有？"></a>配对、绑定和加密是不是每次都有？</h2><p>不一定。</p><p>有些 Characteristic 允许连接后直接读取；有些数据要求链路加密，甚至要求经过身份验证。此时双方可能进行配对，生成安全密钥并启用加密。</p><ul><li>Pairing：协商安全能力并生成密钥；</li><li>Bonding：把密钥保存下来，方便以后重连；</li><li>Encryption：使用密钥保护当前链路中的数据。</li></ul><p>它们有关联，但不是同义词。<strong>BLE Connected 也不自动等于已经配对、已经绑定或已经加密。</strong></p><p>如果读取某个 Characteristic 时提示权限或认证错误，应检查它的访问权限和当前安全级别，而不是只看连接状态。</p><h2 id="从连接到收到数据，逐步证明了什么？"><a href="#从连接到收到数据，逐步证明了什么？" class="headerlink" title="从连接到收到数据，逐步证明了什么？"></a>从连接到收到数据，逐步证明了什么？</h2><p>下面这张表很适合在调试时使用：</p><table><thead><tr><th>看到的现象</th><th>能证明什么</th><th>还不能证明什么</th></tr></thead><tbody><tr><td>扫描到设备</td><td>广播可被接收，手机能发现它</td><td>可以建立连接</td></tr><tr><td>Connected</td><td>BLE 链路已经建立</td><td>GATT Service 正常、业务正常</td></tr><tr><td>MTU Exchange 完成</td><td>双方协商了 ATT 消息大小</td><td>Service 已发现、吞吐一定更高</td></tr><tr><td>找到目标 Service</td><td>GATT Client 发现了这组功能</td><td>目标 Characteristic 可正常使用</td></tr><tr><td>找到 Characteristic</td><td>UUID 和 Handle 已发现</td><td>权限满足、数据格式正确</td></tr><tr><td>CCCD 已写为开启值</td><td>Client 已请求 Notify 或 Indicate</td><td>Server 一定会产生业务数据</td></tr><tr><td>收到第一条 Notification</td><td>Server 到 Client 的这条数据路径已跑通</td><td>所有命令、异常和重连都正常</td></tr><tr><td>一次完整且被正确解析的读写成功</td><td>本次操作的业务格式和方向基本正确</td><td>长时间稳定性和所有边界情况正常</td></tr></tbody></table><p>所以，“连接上了但不能用”并不矛盾。它只是说明故障范围已经从广播和连接阶段，缩小到了后续阶段。</p><h2 id="初学者最容易遇到的五个误区"><a href="#初学者最容易遇到的五个误区" class="headerlink" title="初学者最容易遇到的五个误区"></a>初学者最容易遇到的五个误区</h2><h3 id="误区一：广播里有-Service-UUID，连接后就一定能用"><a href="#误区一：广播里有-Service-UUID，连接后就一定能用" class="headerlink" title="误区一：广播里有 Service UUID，连接后就一定能用"></a>误区一：广播里有 Service UUID，连接后就一定能用</h3><p>广播中的 Service UUID 主要帮助扫描端识别设备。真正的 Service、Characteristic、权限和数据仍要在连接后通过 GATT 访问。</p><h3 id="误区二：能-Read，就一定能-Notify"><a href="#误区二：能-Read，就一定能-Notify" class="headerlink" title="误区二：能 Read，就一定能 Notify"></a>误区二：能 Read，就一定能 Notify</h3><p>Read 和 Notify 是不同能力。Notify 还需要 Client 完成订阅，Server 也要在合适时机主动发送数据。</p><h3 id="误区三：Notify-和-Indicate-完全一样"><a href="#误区三：Notify-和-Indicate-完全一样" class="headerlink" title="误区三：Notify 和 Indicate 完全一样"></a>误区三：Notify 和 Indicate 完全一样</h3><p>两者都由 Server 主动发送，但 Indicate 要求 ATT 层确认，Notify 不要求。具体选择要看实时性、流量和可靠性需求。</p><h3 id="误区四：UUID-就是数据内容"><a href="#误区四：UUID-就是数据内容" class="headerlink" title="误区四：UUID 就是数据内容"></a>误区四：UUID 就是数据内容</h3><p>UUID 只说明数据类型，真正内容在 Value 中。Value 往往是一串字节，还要按照该 Characteristic 的格式解释。</p><h3 id="误区五：MTU-越大，速度一定越快"><a href="#误区五：MTU-越大，速度一定越快" class="headerlink" title="误区五：MTU 越大，速度一定越快"></a>误区五：MTU 越大，速度一定越快</h3><p>MTU 只是影响一次 ATT 消息可以携带的大小。实际速度还受到连接间隔、PHY、数据长度、设备处理速度和应用交互方式等因素影响。</p><h2 id="最简单的动手顺序"><a href="#最简单的动手顺序" class="headerlink" title="最简单的动手顺序"></a>最简单的动手顺序</h2><p>准备一台支持 BLE 的设备和一个能够查看 GATT 的调试工具，然后只做下面几步：</p><ol><li>扫描设备，观察名称、信号强度和广播内容；</li><li>建立连接，确认 Connected；</li><li>展开 Service 列表，先找 Device Information 和 Battery Service；</li><li>查看 Characteristic 的 UUID、Properties 和 Value；</li><li>对允许 Read 的 Characteristic 执行一次读取；</li><li>对允许 Notify 的 Characteristic 开启订阅，观察 CCCD 和后续数据；</li><li>断开再连接一次，观察哪些步骤需要重新执行。</li></ol><p>不要随意向含义未知的 Characteristic 写入数据。它可能代表重启、清空数据、进入升级模式或其他控制命令。</p><p>第一次动手的目标不是记住所有 UUID，而是建立一条判断链：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">能扫描到吗？</span><br><span class="line">  -&gt; 能连接吗？</span><br><span class="line">  -&gt; 能发现目标 Service 吗？</span><br><span class="line">  -&gt; 能找到目标 Characteristic 吗？</span><br><span class="line">  -&gt; 权限和安全条件满足吗？</span><br><span class="line">  -&gt; CCCD 订阅成功吗？</span><br><span class="line">  -&gt; 第一条读、写或通知出现了吗？</span><br></pre></td></tr></table></figure><h2 id="一页小抄"><a href="#一页小抄" class="headerlink" title="一页小抄"></a>一页小抄</h2><table><thead><tr><th>名词</th><th>一句话理解</th></tr></thead><tbody><tr><td>Advertising</td><td>设备在连接前发送“我在这里”等信息</td></tr><tr><td>Scanning</td><td>手机收听附近广播</td></tr><tr><td>Connection</td><td>双方建立可持续交换数据的 BLE 链路</td></tr><tr><td>GATT Server</td><td>保存并提供 GATT 数据库的一方</td></tr><tr><td>GATT Client</td><td>发现、读取、写入和订阅数据的一方</td></tr><tr><td>Service</td><td>一组相关功能</td></tr><tr><td>Characteristic</td><td>一个具体数据项及其操作方式</td></tr><tr><td>Descriptor</td><td>Characteristic 的补充说明或配置</td></tr><tr><td>UUID</td><td>Attribute 的类型标识</td></tr><tr><td>Handle</td><td>GATT 数据库中具体条目的编号</td></tr><tr><td>CCCD</td><td>Client 用来开启或关闭 Notify、Indicate 的配置项</td></tr><tr><td>ATT</td><td>操作和传送 Attribute 的底层协议</td></tr><tr><td>MTU</td><td>单个 ATT PDU 允许的最大尺寸</td></tr></tbody></table><h2 id="最后再看一次完整过程"><a href="#最后再看一次完整过程" class="headerlink" title="最后再看一次完整过程"></a>最后再看一次完整过程</h2><p>一台 BLE 设备“真正可用”，通常不是一个瞬间，而是一串连续的小成功：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">广播可见</span><br><span class="line">  -&gt; 连接建立</span><br><span class="line">  -&gt; 安全条件满足</span><br><span class="line">  -&gt; 如有需要，完成 MTU 等传输参数协商</span><br><span class="line">  -&gt; Service / Characteristic / Descriptor 被发现</span><br><span class="line">  -&gt; Read、Write 或 CCCD 订阅完成</span><br><span class="line">  -&gt; 第一条业务数据成功传输</span><br></pre></td></tr></table></figure><p>以后再看到“BLE 已连接但没有数据”，不要把所有问题都叫作“连接失败”。沿着这条时间线向下检查，很快就能知道自己是在找不到服务、订阅没有完成，还是业务命令根本没有开始。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://www.bluetooth.com/bluetooth-le-primer/">Bluetooth SIG：Bluetooth Low Energy Primer</a></li><li><a href="https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-61/out/en/host/generic-attribute-profile--gatt-.html">Bluetooth SIG：Generic Attribute Profile</a></li><li><a href="https://www.bluetooth.com/specifications/specs/battery-service/">Bluetooth SIG：Battery Service 1.1</a></li><li><a href="https://docs.zephyrproject.org/latest/services/connectivity/bluetooth/api/gatt.html">Zephyr：Generic Attribute Profile 文档</a></li><li><a href="https://docs.zephyrproject.org/latest/samples/bluetooth/mtu_update/README.html">Zephyr：MTU Update 示例</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/ble-gatt-connection-basics/</id>
    <link href="https://onium.top/posts/ble-gatt-connection-basics/"/>
    <published>2026-08-02T07:00:00.000Z</published>
    <summary>
      <![CDATA[<p>打开一个蓝牙调试工具，点下 Connect，页面很快显示“Connected”。这是不是说明手机已经能读到设备数据，也能正常控制设备了？</p>
<p>不一定。</p>
<p><strong>BLE 连接成功，只表示两台设备已经建立了一条无线链路。</strong> 后面通常还要发现 Service、找到 Characteristic、确认读写方式、订阅通知，应用数据才真正开始流动。</p>]]>
    </summary>
    <title>BLE GATT 入门：手机连上设备后，到底发生了什么？</title>
    <updated>2026-08-02T15:49:56.060Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Matter" scheme="https://onium.top/tags/matter/"/>
    <category term="Commissioning" scheme="https://onium.top/tags/commissioning/"/>
    <category term="Thread" scheme="https://onium.top/tags/thread/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="入网" scheme="https://onium.top/tags/%E5%85%A5%E7%BD%91/"/>
    <content>
      <![CDATA[<p>Zigbee 设备打开允许加入、搜索网络、获得密钥，似乎就能完成入网。Matter over Thread 为什么还要扫码、连接 Bluetooth LE、建立临时安全通道、验证设备证书、写入长期身份、加入 Thread，再切换到 IP 网络重新连接？</p><p>这些步骤是在把简单问题复杂化，还是在解决不同的问题？</p><span id="more"></span><p>本文跟随一台刚恢复出厂的门磁传感器，从拆箱一直走到 App 能稳定显示“门已打开”或“门已关闭”。每走一步，我们都回答五个问题：</p><ol><li>现在是谁在和谁通信？</li><li>设备得到了什么？</li><li>为什么需要这一步？</li><li>Zigbee 在相近阶段怎样处理？</li><li>成功到这里，还不能证明什么？</li></ol><h2 id="先限定比较范围"><a href="#先限定比较范围" class="headerlink" title="先限定比较范围"></a>先限定比较范围</h2><p>“Matter 入网”和“Zigbee 入网”都不只有一种路径。为了让两条时间线能够真正对齐，本文只比较两个最常见的首次入网场景：</p><ul><li>Matter over Thread：恢复出厂的设备，通过常见的 Bluetooth LE 临时通道，加入已有 Thread 网络和 Matter Fabric；</li><li>Zigbee：Factory New 设备，通过 Network Steering，加入采用集中式安全模型的 Zigbee 网络。</li></ul><p>本文不把下面这些分支混进主线：</p><ul><li>已经连接 IP 网络的 Matter On-network Commissioning；</li><li>Matter 的第二管理员和多 Fabric；</li><li>Zigbee Rejoin、Touchlink、分布式安全网络；</li><li>新版 Zigbee 增加的 Zigbee Direct、动态密钥协商和批量 commissioning。</li></ul><p>这些分支会改变部分消息和安全步骤，但不会改变本文最重要的分析方法：<strong>先分清网络接入、初始信任、长期身份和应用可用是四件不同的事。</strong></p><h2 id="第-0-章：阅读前先认识几个角色"><a href="#第-0-章：阅读前先认识几个角色" class="headerlink" title="第 0 章：阅读前先认识几个角色"></a>第 0 章：阅读前先认识几个角色</h2><p>先不要急着记 PASE、CASE、NOC 等缩写。理解下面这些角色，已经足够开始阅读。</p><table><thead><tr><th>名词</th><th>先用一句人话理解</th><th>不要误解成</th></tr></thead><tbody><tr><td>Matter</td><td>规定设备如何建立信任、描述功能和相互控制的标准</td><td>一种无线信号</td></tr><tr><td>Thread</td><td>面向低功耗设备的 IPv6 Mesh 网络</td><td>一套灯、门锁、传感器应用协议</td></tr><tr><td>Matter over Thread</td><td>Matter 应用运行在 Thread 网络上的组合</td><td>Matter 和 Thread 是同一个协议</td></tr><tr><td>Zigbee</td><td>从 Mesh 网络、安全到设备应用模型的一套协议体系</td><td>Thread 的旧名称</td></tr><tr><td>Commissioning</td><td>把新设备安全登记进家庭系统的完整过程</td><td>只连上无线网络</td></tr><tr><td>Commissioner</td><td>给 Matter 新设备办理登记的一方，可能是手机或家庭中枢</td><td>必然就是 Border Router</td></tr><tr><td>Commissionee</td><td>正在等待办理入网的 Matter 设备</td><td>一台特殊类型的硬件</td></tr><tr><td>Thread Border Router</td><td>在 Thread Mesh 与家庭 Wi-Fi、Ethernet 等 IP 网络之间转发数据</td><td>Zigbee Coordinator 或协议翻译器</td></tr><tr><td>Matter Fabric</td><td>一组共享管理和信任关系的 Matter 节点</td><td>一张 Thread 网络或一个 Zigbee PAN</td></tr><tr><td>Zigbee Coordinator</td><td>创建 Zigbee 网络的核心角色</td><td>所有 Zigbee Router</td></tr><tr><td>Zigbee Trust Center</td><td>管理 Zigbee 设备准入和安全材料的角色</td><td>普通父节点</td></tr></tbody></table><p>在实际产品里，一个家庭中枢可能同时承担 Matter Commissioner、Matter Controller 和 Thread Border Router；一个 Zigbee 网关也可能同时包含 Coordinator、Trust Center 和应用管理功能。</p><p><strong>装在同一个盒子里，不代表这些角色是同一件事。</strong></p><h3 id="两边的简化关系"><a href="#两边的简化关系" class="headerlink" title="两边的简化关系"></a>两边的简化关系</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">Matter over Thread</span><br><span class="line"></span><br><span class="line">手机或家庭中枢</span><br><span class="line">  ├── Commissioner：办理入网</span><br><span class="line">  ├── Controller：日常读取和控制</span><br><span class="line">  └── 可能还包含 Thread Border Router</span><br><span class="line">                         │</span><br><span class="line">                         │ 在 Thread 与家庭 IP 网络间路由</span><br><span class="line">                         ▼</span><br><span class="line">                 Thread Mesh 中的门磁</span><br><span class="line"></span><br><span class="line">Matter Fabric：</span><br><span class="line">记录长期身份、管理关系和访问权限</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Zigbee</span><br><span class="line"></span><br><span class="line">Zigbee 网关</span><br><span class="line">  ├── Coordinator：创建网络</span><br><span class="line">  ├── Trust Center：管理准入和安全</span><br><span class="line">  └── 应用管理：识别门磁能力</span><br><span class="line">             │</span><br><span class="line">             ▼</span><br><span class="line">      Router 或直接父节点</span><br><span class="line">             │</span><br><span class="line">             ▼</span><br><span class="line">          Zigbee 门磁</span><br></pre></td></tr></table></figure><p>如果还分不清三者的位置，可以先阅读<a href="/posts/matter-thread-zigbee-layers/">《Matter、Thread 与 Zigbee：先分清它们在哪一层》</a>。</p><h2 id="第-1-章：两台门磁加入的是同一种“网”吗？"><a href="#第-1-章：两台门磁加入的是同一种“网”吗？" class="headerlink" title="第 1 章：两台门磁加入的是同一种“网”吗？"></a>第 1 章：两台门磁加入的是同一种“网”吗？</h2><h3 id="先提出疑问"><a href="#先提出疑问" class="headerlink" title="先提出疑问"></a>先提出疑问</h3><p>Matter over Thread 和 Zigbee 都可能使用 2.4 GHz IEEE 802.15.4。既然无线底层相似，为什么入网流程不能也做成一样？</p><h3 id="Zigbee-更像一套完整的小区系统"><a href="#Zigbee-更像一套完整的小区系统" class="headerlink" title="Zigbee 更像一套完整的小区系统"></a>Zigbee 更像一套完整的小区系统</h3><p>在本文讨论的经典集中式 Zigbee 网络里，设备从扫描网络开始，随后建立父子关系、获得网络地址和 Network Key，最后被网关识别出应用能力。</p><p>Zigbee 自己定义了：</p><ul><li>Mesh 网络怎样形成；</li><li>网络地址怎样使用；</li><li>Trust Center 怎样管理安全准入；</li><li>NWK、APS 层怎样保护通信；</li><li>Endpoint、Cluster、Attribute 怎样表达设备功能。</li></ul><p>它很像一个同时负责道路、门禁、住户管理和物业服务的小区系统。</p><h3 id="Matter-over-Thread-是两层组合"><a href="#Matter-over-Thread-是两层组合" class="headerlink" title="Matter over Thread 是两层组合"></a>Matter over Thread 是两层组合</h3><p>Matter over Thread 则把问题拆开：</p><ul><li>Thread 回答：设备怎样获得一条低功耗 IPv6 通信道路？</li><li>Matter 回答：设备是谁、属于哪个家庭信任域、谁可以控制它、它有哪些标准能力？</li></ul><p>因此，一台 Matter over Thread 门磁要完成两类登记：</p><ol><li>获得 Thread 网络资料并接入 Thread Mesh；</li><li>获得 Matter 运行身份并加入一个 Fabric。</li></ol><p>这两个结果经常在同一次用户操作中完成，但不是同一层协议状态。</p><h3 id="为什么要这样拆开？"><a href="#为什么要这样拆开？" class="headerlink" title="为什么要这样拆开？"></a>为什么要这样拆开？</h3><p>拆开的好处是：</p><ul><li>Matter 身份不必绑定在某个父节点或某个临时 IPv6 路由位置上；</li><li>同一个 Matter Fabric 可以包含 Thread、Wi-Fi 和 Ethernet 设备；</li><li>Thread Border Router 只需要路由 IP 数据，不必理解门磁、灯或门锁；</li><li>Matter 可以在应用层统一身份、权限和数据模型。</li></ul><p>代价也很直接：</p><ul><li>网络凭据和 Matter 身份凭据要分别管理；</li><li>配网要跨越 Bluetooth LE、Thread、IPv6 和 Matter 安全会话；</li><li>“连接成功”出现了更多不同层次。</li></ul><blockquote><p><strong>如果不拆开会怎样？</strong></p><p>网络拓扑、应用身份和生态管理会更加紧密地绑定在一起。系统可能更直接，但跨不同 IP 承载、多管理员和统一访问控制会更依赖网关或厂商自己的设计。</p></blockquote><blockquote><p><strong>到这里证明了什么？</strong></p><p>我们只理解了两种架构的目标，还没有开始真正入网。</p></blockquote><h2 id="第-2-章：为什么要先打开一个“允许加入”的窗口？"><a href="#第-2-章：为什么要先打开一个“允许加入”的窗口？" class="headerlink" title="第 2 章：为什么要先打开一个“允许加入”的窗口？"></a>第 2 章：为什么要先打开一个“允许加入”的窗口？</h2><h3 id="Matter：设备先表示“我现在可以办理登记”"><a href="#Matter：设备先表示“我现在可以办理登记”" class="headerlink" title="Matter：设备先表示“我现在可以办理登记”"></a>Matter：设备先表示“我现在可以办理登记”</h3><p>恢复出厂的 Matter 设备通常会进入可 commissioning 状态，或者由用户按键主动打开 Commissioning Window。设备随后通过支持的发现方式告诉附近的 Commissioner：“我现在接受入网。”</p><p>在本文的典型场景里，这通常包括 Bluetooth LE 广播。</p><p>窗口不会永远开放，因为长期允许陌生控制端尝试建立初始会话，会增加无意义连接和攻击面。用户明确触发配网，也能把一次现实世界中的操作与后续网络操作联系起来。</p><h3 id="Zigbee：网关和设备两边都要准备好"><a href="#Zigbee：网关和设备两边都要准备好" class="headerlink" title="Zigbee：网关和设备两边都要准备好"></a>Zigbee：网关和设备两边都要准备好</h3><p>Zigbee 网关通常先打开 Permit Join。Factory New 设备启动 Network Steering，在配置的信道集合中寻找允许加入的网络。</p><p>这里要区分两件事：</p><ul><li>Permit Join：网络允许新设备提出申请；</li><li>设备最终被接纳：还要经过关联和安全准入。</li></ul><p>看到 Permit Join 已打开，不代表任何附近设备都已经成为网络成员。</p><h3 id="可以怎样类比？"><a href="#可以怎样类比？" class="headerlink" title="可以怎样类比？"></a>可以怎样类比？</h3><table><thead><tr><th>目的</th><th>Matter over Thread</th><th>Zigbee</th></tr></thead><tbody><tr><td>设备表示愿意办理入网</td><td>Commissioning Window &#x2F; Commissionable 广播</td><td>Factory New + Network Steering</td></tr><tr><td>网络侧允许新设备申请</td><td>Commissioner 开始添加流程</td><td>Permit Join</td></tr><tr><td>最终准入</td><td>后续 PASE、Attestation、NOC 等</td><td>Association、Trust Center 安全流程等</td></tr></tbody></table><p>Commissioning Window 和 Permit Join 的目的相近，但它们不是同一条协议命令。</p><blockquote><p><strong>如果没有窗口会怎样？</strong></p><p>设备或网络可能长期接受未经用户触发的入网尝试，既浪费资源，也难以把“用户正在添加这台设备”与无线世界里的请求对应起来。</p></blockquote><blockquote><p><strong>到这里证明了什么？</strong></p><p>只证明双方进入了“可以尝试添加”的状态，还没有找到彼此，更没有建立安全关系。</p></blockquote><h2 id="第-3-章：为什么-Matter-要扫码，而-Zigbee-常常自己搜索网络？"><a href="#第-3-章：为什么-Matter-要扫码，而-Zigbee-常常自己搜索网络？" class="headerlink" title="第 3 章：为什么 Matter 要扫码，而 Zigbee 常常自己搜索网络？"></a>第 3 章：为什么 Matter 要扫码，而 Zigbee 常常自己搜索网络？</h2><h3 id="扫码不是无线连接"><a href="#扫码不是无线连接" class="headerlink" title="扫码不是无线连接"></a>扫码不是无线连接</h3><p>Matter 二维码或手动配对码携带的是 Onboarding Payload，也就是帮助 Commissioner 找到目标设备并建立初始信任的引导信息。</p><p>对本文主线最重要的两项是：</p><ul><li>Discriminator：帮助从附近多个待配网设备中缩小目标；</li><li>Setup Passcode：后面建立初始安全会话时使用的秘密。</li></ul><p>二维码不包含真实家庭的 Thread Dataset，也不会因为被摄像头扫到，就自动连接设备。</p><p>可以把它理解为：</p><blockquote><p>二维码告诉接待员“应该找哪位新住户，以及第一次见面用什么暗号”，而不是直接把小区总钥匙印在包装上。</p></blockquote><h3 id="Matter-怎样发现设备？"><a href="#Matter-怎样发现设备？" class="headerlink" title="Matter 怎样发现设备？"></a>Matter 怎样发现设备？</h3><p>典型过程是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">用户扫描二维码</span><br><span class="line">  -&gt; App 解析引导信息</span><br><span class="line">  -&gt; 手机扫描附近 Commissionable 广播</span><br><span class="line">  -&gt; 使用 Discriminator 等信息筛选目标</span><br><span class="line">  -&gt; 建立 Bluetooth LE 连接</span><br></pre></td></tr></table></figure><p>Bluetooth LE Connected 只说明手机和设备之间有了一条近距离通信链路。</p><h3 id="Zigbee-怎样发现网络？"><a href="#Zigbee-怎样发现网络？" class="headerlink" title="Zigbee 怎样发现网络？"></a>Zigbee 怎样发现网络？</h3><p>经典 Network Steering 更像设备主动找小区：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">设备扫描候选信道</span><br><span class="line">  -&gt; 发送 Beacon Request</span><br><span class="line">  -&gt; 接收周围网络的 Beacon</span><br><span class="line">  -&gt; 判断网络是否允许加入</span><br><span class="line">  -&gt; 比较候选网络和父节点</span><br><span class="line">  -&gt; 选择目标网络</span><br></pre></td></tr></table></figure><p>设备看到 Beacon，只证明它发现了网络。它还没有完成 Association，也没有获得可用的 Network Key。</p><h3 id="为什么两边选择不同？"><a href="#为什么两边选择不同？" class="headerlink" title="为什么两边选择不同？"></a>为什么两边选择不同？</h3><p>Matter 的用户通常是在 App 中明确添加某一台商品设备，二维码能帮助用户指认目标，并提供设备独有的初始秘密。Zigbee Network Steering 则更强调由设备扫描附近符合条件的 Zigbee 网络，再进入网络侧准入流程。</p><p>这不是“扫码一定比扫描安全”，而是两种系统如何把现实世界中的用户操作与网络申请绑定起来的不同选择。</p><blockquote><p><strong>如果 Matter 只有 BLE 广播、没有配对码会怎样？</strong></p><p>手机可能知道附近有待配网设备，却缺少设备独有的初始秘密来建立后续安全会话，也更难确认用户指向的是哪一台同型号设备。</p></blockquote><blockquote><p><strong>到这里证明了什么？</strong></p><p>扫码证明 App 获得了引导信息；BLE 连接证明双方可以传数据。两者都不能证明 Thread 或 Matter 入网成功。</p></blockquote><h2 id="第-4-章：Bluetooth-LE-已经连接，为什么还需要-PASE？"><a href="#第-4-章：Bluetooth-LE-已经连接，为什么还需要-PASE？" class="headerlink" title="第 4 章：Bluetooth LE 已经连接，为什么还需要 PASE？"></a>第 4 章：Bluetooth LE 已经连接，为什么还需要 PASE？</h2><h3 id="“电话接通”不等于“进入保密会议室”"><a href="#“电话接通”不等于“进入保密会议室”" class="headerlink" title="“电话接通”不等于“进入保密会议室”"></a>“电话接通”不等于“进入保密会议室”</h3><p>Bluetooth LE 解决的是近距离传输问题。它不自动证明对端就是二维码对应的设备，也不意味着 Thread 网络资料可以直接明文发送。</p><p>手机和设备会利用 Setup Passcode 建立一条本次 commissioning 使用的临时安全会话。Matter 把这一步称为 <strong>PASE</strong>，全称 Passcode Authenticated Session Establishment。</p><p>先记住一句话：</p><blockquote><p>PASE 是配网阶段的临时安全通道，不是设备日常运行的长期身份证。</p></blockquote><h3 id="PASE-成功后能做什么？"><a href="#PASE-成功后能做什么？" class="headerlink" title="PASE 成功后能做什么？"></a>PASE 成功后能做什么？</h3><p>Commissioner 可以通过受保护的 Matter 会话执行后续 commissioning 操作，例如：</p><ul><li>读取设备的 commissioning 能力；</li><li>启动 Fail-safe；</li><li>配置法规或时间相关信息；</li><li>请求设备认证材料；</li><li>写入 Matter 运行凭据；</li><li>配置 Thread 网络。</li></ul><p>Fail-safe 可以理解为“配网安全绳”：如果流程中途失败或超时，设备能够回退未最终确认的配置，避免长期停在只完成一半的状态。</p><h3 id="Zigbee-中哪个步骤最像-PASE？"><a href="#Zigbee-中哪个步骤最像-PASE？" class="headerlink" title="Zigbee 中哪个步骤最像 PASE？"></a>Zigbee 中哪个步骤最像 PASE？</h3><p>没有一个完全相同的步骤。</p><p>Zigbee Association 主要建立设备的网络成员关系和父子关系；初始 Link Key、Install Code 派生 Key 等则承担初始安全引导的一部分目的。它们与 PASE 有交集，但协议层次和生命周期不同。</p><table><thead><tr><th>问题</th><th>Matter PASE</th><th>Zigbee 经典加入</th></tr></thead><tbody><tr><td>是否建立临时安全会话</td><td>是</td><td>不按 PASE 方式建立</td></tr><tr><td>是否建立父子网络关系</td><td>否</td><td>Association 负责</td></tr><tr><td>初始秘密来源</td><td>Setup Passcode</td><td>预配置 Link Key、Install Code 派生 Key等</td></tr><tr><td>是否用于长期日常单播</td><td>否</td><td>初始 Key 是否继续使用取决于安全策略</td></tr></tbody></table><blockquote><p><strong>如果没有 PASE 会怎样？</strong></p><p>Thread Dataset、证书配置和其他 commissioning 数据将缺少 Matter 定义的初始安全会话保护，初始秘密也难以安全过渡到长期身份。</p></blockquote><blockquote><p><strong>到这里证明了什么？</strong></p><p>PASE 成功只证明双方建立了临时安全会话。设备仍可能没有 Thread 网络资料、没有 NOC，也没有加入 Fabric。</p></blockquote><h2 id="第-5-章：有了配网码，为什么还要验证设备是不是可信产品？"><a href="#第-5-章：有了配网码，为什么还要验证设备是不是可信产品？" class="headerlink" title="第 5 章：有了配网码，为什么还要验证设备是不是可信产品？"></a>第 5 章：有了配网码，为什么还要验证设备是不是可信产品？</h2><h3 id="知道暗号，不等于拥有可信身份证"><a href="#知道暗号，不等于拥有可信身份证" class="headerlink" title="知道暗号，不等于拥有可信身份证"></a>知道暗号，不等于拥有可信身份证</h3><p>Setup Passcode 证明的是双方掌握同一个初始秘密。它不能单独回答：</p><ul><li>设备是否由它声称的厂商制造；</li><li>设备是否持有对应的设备私钥；</li><li>产品身份和合规声明是否能形成可信链条；</li><li>当前响应是否来自一次旧通信的重放。</li></ul><p>Matter 因此还有 <strong>Device Attestation</strong>，也就是设备认证。</p><h3 id="用“身份证链”理解-Attestation"><a href="#用“身份证链”理解-Attestation" class="headerlink" title="用“身份证链”理解 Attestation"></a>用“身份证链”理解 Attestation</h3><p>不用先背缩写，先看角色：</p><ol><li>每台设备有自己的设备证书和私钥；</li><li>设备证书由上级产品认证机构签发；</li><li>Commissioner 信任更上层的根；</li><li>Commissioner 发送一次性随机挑战；</li><li>设备使用私钥对本次挑战相关数据签名；</li><li>Commissioner 验证证书链、签名和产品声明。</li></ol><p>专业名称对应如下：</p><table><thead><tr><th>白话角色</th><th>Matter 名称</th></tr></thead><tbody><tr><td>每台设备的身份证</td><td>Device Attestation Certificate，DAC</td></tr><tr><td>签发设备证书的上级</td><td>Product Attestation Intermediate，PAI</td></tr><tr><td>信任链根</td><td>Product Attestation Authority，PAA</td></tr><tr><td>产品合规声明</td><td>Certification Declaration，CD</td></tr></tbody></table><p>PAA 根证书通常来自 Commissioner 的信任库，不是简单要求设备“自己拿一张根证书证明自己”。</p><h3 id="Attestation-能证明到什么程度？"><a href="#Attestation-能证明到什么程度？" class="headerlink" title="Attestation 能证明到什么程度？"></a>Attestation 能证明到什么程度？</h3><p>它帮助 Commissioner 验证设备持有的认证身份和产品声明。它不自动证明：</p><ul><li>固件永远没有漏洞；</li><li>设备运行环境没有被破坏；</li><li>用户一定应该授权这台设备进入家庭；</li><li>入网后的每一次业务操作都天然允许。</li></ul><p>设备认证是准入证据之一，最终策略仍由 Commissioner 和生态决定。</p><h3 id="Zigbee-有没有完全对应的步骤？"><a href="#Zigbee-有没有完全对应的步骤？" class="headerlink" title="Zigbee 有没有完全对应的步骤？"></a>Zigbee 有没有完全对应的步骤？</h3><p>在本文比较的经典 Zigbee 3.x 集中式安全加入中，没有与 Matter 设备证书链认证完全等价的通用步骤。</p><p>Trust Center 可以根据设备信息和安全策略决定是否接纳；Install Code 可以让设备与 Trust Center 拥有设备唯一的初始秘密。但“证明双方知道唯一秘密”与“验证厂商、产品声明和设备证书链”仍然是不同问题。</p><p>较新的 Zigbee 版本继续扩展 commissioning 和安全能力，因此具体项目必须回到目标 Zigbee Core、BDB 与安全策略确认，不能把本文的经典路径当成所有版本的唯一实现。</p><blockquote><p><strong>如果没有 Attestation 会怎样？</strong></p><p>Commissioner 仍可能依靠配网码建立初始加密，但更难用标准化证书链验证设备声称的产品身份和设备私钥。</p></blockquote><blockquote><p><strong>到这里证明了什么？</strong></p><p>Attestation 成功证明认证材料通过了 Commissioner 的验证流程；它不证明 Thread 已连接，也不证明最终 CommissioningComplete 已完成。</p></blockquote><h2 id="第-6-章：为什么既要-Thread-Dataset，又要-Matter-NOC？"><a href="#第-6-章：为什么既要-Thread-Dataset，又要-Matter-NOC？" class="headerlink" title="第 6 章：为什么既要 Thread Dataset，又要 Matter NOC？"></a>第 6 章：为什么既要 Thread Dataset，又要 Matter NOC？</h2><p>这是整篇文章最重要的问题。</p><h3 id="两份材料回答两个不同问题"><a href="#两份材料回答两个不同问题" class="headerlink" title="两份材料回答两个不同问题"></a>两份材料回答两个不同问题</h3><p><strong>Thread Active Operational Dataset</strong> 回答：</p><blockquote><p>设备怎样进入这张 Thread 网络？</p></blockquote><p>它描述目标 Thread 网络的关键参数和安全材料，例如信道、网络标识、Mesh-Local Prefix 和网络安全信息。它不是适合公开分享的普通配置文本。</p><p><strong>Node Operational Certificate，NOC</strong> 回答：</p><blockquote><p>设备以什么 Node 身份加入哪个 Matter Fabric？</p></blockquote><p>可以把二者理解为：</p><ul><li>Thread Dataset：小区道路和门禁的入场资料；</li><li>NOC：写有住户身份和家庭归属的长期电子证件。</li></ul><h3 id="Matter-长期身份怎样产生？"><a href="#Matter-长期身份怎样产生？" class="headerlink" title="Matter 长期身份怎样产生？"></a>Matter 长期身份怎样产生？</h3><p>典型流程可以简化为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">设备生成运行密钥对</span><br><span class="line">  -&gt; 设备提交 CSR</span><br><span class="line">  -&gt; Fabric 管理侧签发 NOC</span><br><span class="line">  -&gt; Commissioner 写入受信任根</span><br><span class="line">  -&gt; Commissioner 写入 NOC</span><br><span class="line">  -&gt; 建立 Node ID、Fabric 和初始管理关系</span><br></pre></td></tr></table></figure><p>设备的运行私钥应留在设备内部。CSR 是证书签名请求，不是把私钥交给 Commissioner。</p><p>在典型流程中，AddNOC 还会帮助建立初始管理员主体和访问控制关系。日后 Matter 的读取、写入、命令和订阅仍要经过访问控制判断，而不是“知道设备 IP 地址就可以任意操作”。</p><h3 id="Zigbee-用哪些材料？"><a href="#Zigbee-用哪些材料？" class="headerlink" title="Zigbee 用哪些材料？"></a>Zigbee 用哪些材料？</h3><p>Zigbee 没有一张与 NOC 完全等价的单一证件。几个常见概念分别承担不同作用：</p><table><thead><tr><th>Zigbee 概念</th><th>主要作用</th></tr></thead><tbody><tr><td>EUI-64</td><td>设备长期标识</td></tr><tr><td>16 位短地址</td><td>当前网络中的运行地址</td></tr><tr><td>Network Key</td><td>保护 Zigbee NWK 层通信的网络共享密钥</td></tr><tr><td>Trust Center Link Key</td><td>设备与 Trust Center 之间的安全管理材料</td></tr><tr><td>Install Code 派生 Key</td><td>设备唯一的初始安全引导材料</td></tr></tbody></table><p>Network Key 让设备参与受保护的 Zigbee 网络通信，但它不是某台设备独有的运行证书。短地址适合当前网络中的高效寻址，但也不等于长期产品身份。</p><h3 id="最容易记错的几个等式"><a href="#最容易记错的几个等式" class="headerlink" title="最容易记错的几个等式"></a>最容易记错的几个等式</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Thread Dataset ≠ Matter NOC</span><br><span class="line">Matter Fabric ≠ Thread Network</span><br><span class="line">Matter Fabric ≠ Zigbee PAN</span><br><span class="line">Matter NOC ≠ Zigbee Network Key</span><br><span class="line">Matter Node ID ≠ Zigbee Short Address</span><br><span class="line">Setup Passcode ≠ Zigbee Install Code</span><br></pre></td></tr></table></figure><p>它们可以在“网络凭据”“长期身份”“初始秘密”等目的层面比较，但不能在实现、抓包或日志里互换。</p><blockquote><p><strong>如果只有 Dataset、没有 NOC 会怎样？</strong></p><p>设备可以获得 Thread 网络连接，却缺少加入 Matter Fabric 的标准长期身份。</p></blockquote><blockquote><p><strong>如果只有 NOC、没有 Dataset 会怎样？</strong></p><p>设备可能已经准备好 Matter 身份，却没有进入目标 Thread 网络的道路。</p></blockquote><blockquote><p><strong>到这里证明了什么？</strong></p><p>NOC 写入证明 Fabric 运行凭据已经配置到相应阶段。它不等于设备已经成功 Thread Attach，也不等于 CASE 和 CommissioningComplete 已完成。</p></blockquote><h2 id="第-7-章：设备怎样真正加入-Thread？Zigbee-又怎样加入自己的网络？"><a href="#第-7-章：设备怎样真正加入-Thread？Zigbee-又怎样加入自己的网络？" class="headerlink" title="第 7 章：设备怎样真正加入 Thread？Zigbee 又怎样加入自己的网络？"></a>第 7 章：设备怎样真正加入 Thread？Zigbee 又怎样加入自己的网络？</h2><h3 id="Matter：通过-PASE-下发-Thread-入场资料"><a href="#Matter：通过-PASE-下发-Thread-入场资料" class="headerlink" title="Matter：通过 PASE 下发 Thread 入场资料"></a>Matter：通过 PASE 下发 Thread 入场资料</h3><p>在本文场景里，Commissioner 已经从家庭系统获得目标 Thread Dataset，再通过 PASE 保护的 commissioning 会话配置设备的 Thread 网络。</p><p>高层过程是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Commissioner 配置 Thread Dataset</span><br><span class="line">  -&gt; 要求设备连接目标网络</span><br><span class="line">  -&gt; 设备扫描并找到目标 Thread Partition</span><br><span class="line">  -&gt; 设备寻找可用 Router 或 REED</span><br><span class="line">  -&gt; 建立 Parent-Child 关系</span><br><span class="line">  -&gt; 获得 Thread 网络数据和 IPv6 地址能力</span><br><span class="line">  -&gt; 成为 Child</span><br></pre></td></tr></table></figure><p>Thread 使用 Mesh Link Establishment，简称 MLE，发现和维护邻居关系。本文的电池门磁通常作为 End Device，通过一个 Parent Router 通信。即使是 Router-Eligible 设备，首次 Attach 也先以 Child 身份进入网络。</p><p>Thread Border Router 的任务是把 Thread 与相邻 IP 网络连接起来。它不是负责给门磁解释 Matter Cluster 的应用网关，也不一定是门磁当前的无线父节点。</p><h3 id="Zigbee：先建立网络位置，再完成安全准入"><a href="#Zigbee：先建立网络位置，再完成安全准入" class="headerlink" title="Zigbee：先建立网络位置，再完成安全准入"></a>Zigbee：先建立网络位置，再完成安全准入</h3><p>经典首次 Network Steering 可以简化为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">扫描信道和 Beacon</span><br><span class="line">  -&gt; 选择目标 PAN 与父节点</span><br><span class="line">  -&gt; Association Request</span><br><span class="line">  -&gt; Association Response</span><br><span class="line">  -&gt; 获得 16 位短地址</span><br><span class="line">  -&gt; Trust Center 安全准入</span><br><span class="line">  -&gt; 接收并安装 Network Key</span><br><span class="line">  -&gt; 开始受保护的 NWK 通信</span><br></pre></td></tr></table></figure><p>Association 由 IEEE 802.15.4 MAC 层提供，用来建立网络成员关系。获得短地址说明设备已经有了初步网络位置，但它还必须正确接收、验证并安装安全材料。</p><p>所以：</p><ul><li>Transport Key 已经从发送端发出，不等于接收端已经解密；</li><li>收到 MAC ACK，不等于 Network Key 已安装；</li><li>获得短地址，不等于 BDB commissioning 全部完成。</li></ul><h3 id="两条路径真正对应在哪里？"><a href="#两条路径真正对应在哪里？" class="headerlink" title="两条路径真正对应在哪里？"></a>两条路径真正对应在哪里？</h3><table><thead><tr><th>目标</th><th>Matter over Thread</th><th>Zigbee</th></tr></thead><tbody><tr><td>找到无线网络</td><td>Thread 扫描与发现</td><td>信道扫描与 Beacon</td></tr><tr><td>建立父子关系</td><td>Thread MLE Attach</td><td>Association</td></tr><tr><td>获得网络安全资料</td><td>预先通过 PASE 配置 Dataset</td><td>Trust Center 传输 Network Key</td></tr><tr><td>获得网络地址能力</td><td>Thread IPv6 地址与网络数据</td><td>16 位短地址与 Zigbee NWK 状态</td></tr><tr><td>网络层可通信</td><td>Thread&#x2F;IPv6 可用</td><td>受保护 Zigbee NWK 通信可用</td></tr></tbody></table><p>两边都要解决“找网络、选父节点、获得网络安全材料、开始正常通信”，但凭据怎样送到设备、长期身份放在哪一层，设计明显不同。</p><blockquote><p><strong>如果只看到 Thread 设备成为 Child 会怎样？</strong></p><p>可以确认 Thread 网络层已经进展到 Attach 成功附近，但仍不能确认 Matter CASE、CommissioningComplete 和应用订阅。</p></blockquote><blockquote><p><strong>如果只看到 Zigbee Association Success 会怎样？</strong></p><p>可以确认父子关系和短地址分配已经进展，但仍不能确认 Network Key 安装、TCLK 流程和应用发现。</p></blockquote><h2 id="第-8-章：Thread-已经连上，为什么-Matter-还要重新找设备？"><a href="#第-8-章：Thread-已经连上，为什么-Matter-还要重新找设备？" class="headerlink" title="第 8 章：Thread 已经连上，为什么 Matter 还要重新找设备？"></a>第 8 章：Thread 已经连上，为什么 Matter 还要重新找设备？</h2><h3 id="从临时接待通道切换到正式道路"><a href="#从临时接待通道切换到正式道路" class="headerlink" title="从临时接待通道切换到正式道路"></a>从临时接待通道切换到正式道路</h3><p>前面的 Matter 操作主要通过 Bluetooth LE 上的 PASE 会话完成。设备加入 Thread 后，后续日常通信应走 Thread 承载的 IPv6，而不是长期依赖手机与设备之间的 BLE 连接。</p><p>Commissioner 需要在正式 IP 网络中找到设备。这称为 <strong>Operational Discovery</strong>。Matter 使用 DNS-SD 等机制解析设备当前可用的地址和端口。</p><p>这里有一个很重要的设计：</p><blockquote><p>Matter 身份是 Node 与 Fabric 身份，不是某个固定 IPv6 地址。</p></blockquote><p>Thread 节点可能拥有多类 IPv6 地址，某些地址还会随拓扑变化。Controller 应通过运行态发现解析设备，而不是把 commissioning 时看到的某个地址永久当成设备身份。</p><h3 id="为什么还要建立-CASE？"><a href="#为什么还要建立-CASE？" class="headerlink" title="为什么还要建立 CASE？"></a>为什么还要建立 CASE？</h3><p>找到设备地址以后，双方使用 Fabric 的运行证书建立长期单播安全会话。这称为 <strong>CASE</strong>，全称 Certificate Authenticated Session Establishment。</p><p>可以这样区分：</p><table><thead><tr><th>会话</th><th>使用阶段</th><th>主要信任基础</th><th>用完以后</th></tr></thead><tbody><tr><td>PASE</td><td>初次 commissioning</td><td>Setup Passcode</td><td>不作为日常长期身份</td></tr><tr><td>CASE</td><td>日常运行和正式管理</td><td>Fabric 运行证书</td><td>可按需重建和恢复</td></tr></tbody></table><p>PASE 像门口的一次性接待室，CASE 像正式住户凭证建立的长期安全通信。</p><h3 id="Zigbee-为什么没有同样的通道切换？"><a href="#Zigbee-为什么没有同样的通道切换？" class="headerlink" title="Zigbee 为什么没有同样的通道切换？"></a>Zigbee 为什么没有同样的通道切换？</h3><p>经典 Zigbee 入网从扫描、Association 到后续 Cluster 通信，都留在 Zigbee 协议栈中。设备安装 Network Key 后，会继续通过 Zigbee NWK、APS 和 ZCL 交互。</p><p>它不需要经历“BLE 临时通道 → Thread&#x2F;IPv6 正式通道”的相同切换，因此也没有与 Operational Discovery + CASE 完全等价的一组步骤。</p><p>Zigbee 仍然要处理地址映射、Device Announcement、Link Key 和应用发现，只是问题被组织在另一套协议结构里。</p><blockquote><p><strong>如果没有 Operational Discovery 会怎样？</strong></p><p>Commissioner 可能知道设备的 Fabric 身份，却不知道它现在可以通过哪个 IP 地址和端口访问。</p></blockquote><blockquote><p><strong>如果继续只用 PASE、不建立 CASE 会怎样？</strong></p><p>日常通信将依赖初始配网秘密，难以利用 Fabric 证书、Node 身份和访问控制建立长期管理关系。</p></blockquote><blockquote><p><strong>到这里证明了什么？</strong></p><p>CASE 成功证明双方已通过正式网络和 Fabric 身份建立安全会话。最终 commissioning 仍要完成确认。</p></blockquote><h2 id="第-9-章：为什么还需要-CommissioningComplete？"><a href="#第-9-章：为什么还需要-CommissioningComplete？" class="headerlink" title="第 9 章：为什么还需要 CommissioningComplete？"></a>第 9 章：为什么还需要 CommissioningComplete？</h2><h3 id="配置写完，不等于验收结束"><a href="#配置写完，不等于验收结束" class="headerlink" title="配置写完，不等于验收结束"></a>配置写完，不等于验收结束</h3><p>Commissioner 已经完成设备认证、运行凭据配置和 Thread 网络连接，也已经通过正式网络建立 CASE。最后，它会发送 <strong>CommissioningComplete</strong>。</p><p>这一步的意义可以理解为：</p><ul><li>确认新的运行身份和网络路径确实可用；</li><li>正式结束本次 commissioning；</li><li>解除前面用于失败回滚的 Fail-safe；</li><li>不再把设备停留在“正在办理入住”的中间状态。</li></ul><p>它像装修、通电和证件登记都完成后的最终交房签字。</p><h3 id="Zigbee-怎样宣布完成？"><a href="#Zigbee-怎样宣布完成？" class="headerlink" title="Zigbee 怎样宣布完成？"></a>Zigbee 怎样宣布完成？</h3><p>Zigbee 设备安装 Network Key 并开始受保护通信后，通常还会：</p><ul><li>发送 Device Announcement；</li><li>完成由目标 BDB 版本和 Trust Center 策略要求的 Link Key 相关流程；</li><li>由 BDB 状态机报告 commissioning 结果。</li></ul><p>具体的 TCLK 更新或交换路径取决于目标版本和安全策略。不能看到 Network Key 就一概宣称所有安全步骤完成。</p><h3 id="两边的成功阶梯"><a href="#两边的成功阶梯" class="headerlink" title="两边的成功阶梯"></a>两边的成功阶梯</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Matter over Thread</span><br><span class="line"></span><br><span class="line">发现设备</span><br><span class="line">  -&gt; BLE 连接</span><br><span class="line">  -&gt; PASE</span><br><span class="line">  -&gt; Device Attestation</span><br><span class="line">  -&gt; NOC / Fabric 身份</span><br><span class="line">  -&gt; Thread Attach</span><br><span class="line">  -&gt; Operational Discovery</span><br><span class="line">  -&gt; CASE</span><br><span class="line">  -&gt; CommissioningComplete</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Zigbee</span><br><span class="line"></span><br><span class="line">发现网络</span><br><span class="line">  -&gt; 选择父节点</span><br><span class="line">  -&gt; Association</span><br><span class="line">  -&gt; 获得短地址</span><br><span class="line">  -&gt; 接收并安装 Network Key</span><br><span class="line">  -&gt; 受保护的 NWK 通信</span><br><span class="line">  -&gt; Device Announcement</span><br><span class="line">  -&gt; TCLK / BDB 相应流程完成</span><br></pre></td></tr></table></figure><blockquote><p><strong>如果没有最终完成确认会怎样？</strong></p><p>设备可能保留只完成一部分的网络或身份配置，系统也难以区分“仍在办理”与“已经正式可用”。Matter 的 Fail-safe 正是为了约束这种中间状态。</p></blockquote><blockquote><p><strong>到这里证明了什么？</strong></p><p>CommissioningComplete 成功证明本次 Matter commissioning 正式闭环。它仍不保证生态已经建立稳定订阅，也不保证 App 的设备模型完全正确。</p></blockquote><h2 id="第-10-章：为什么-App-显示“添加成功”，设备仍可能不可用？"><a href="#第-10-章：为什么-App-显示“添加成功”，设备仍可能不可用？" class="headerlink" title="第 10 章：为什么 App 显示“添加成功”，设备仍可能不可用？"></a>第 10 章：为什么 App 显示“添加成功”，设备仍可能不可用？</h2><h3 id="入网成功与业务可用是两个阶段"><a href="#入网成功与业务可用是两个阶段" class="headerlink" title="入网成功与业务可用是两个阶段"></a>入网成功与业务可用是两个阶段</h3><p>一台门磁真正好用，至少还要让平台知道：</p><ul><li>它有哪些 Endpoint；</li><li>它是什么 Device Type；</li><li>它实现了哪些 Cluster；</li><li>门开、门关状态从哪里读取；</li><li>状态变化怎样持续上报；</li><li>当前 Controller 是否有读取或订阅权限。</li></ul><p>Matter Controller 通常会读取设备结构和属性，并建立 Subscribe。订阅建立后，设备才能在约定条件下持续报告状态变化。</p><p>如果 CommissioningComplete 已成功，但从未建立 Subscribe，门磁可能“在网、可信、可寻址”，App 却无法持续得到门状态。</p><h3 id="Zigbee-网关也要做设备-Interview"><a href="#Zigbee-网关也要做设备-Interview" class="headerlink" title="Zigbee 网关也要做设备 Interview"></a>Zigbee 网关也要做设备 Interview</h3><p>Zigbee 网络接入完成后，网关通常还会：</p><ul><li>查询 Node Descriptor；</li><li>查询 Active Endpoints；</li><li>读取 Simple Descriptor；</li><li>读取 Basic 属性；</li><li>识别支持的 Cluster；</li><li>配置 Reporting；</li><li>按需要建立 Binding。</li></ul><p>所以 Zigbee 设备获得短地址或发送 Device Announcement，也不等于网关已经完整识别它。</p><h3 id="把“成功”分成四级"><a href="#把“成功”分成四级" class="headerlink" title="把“成功”分成四级"></a>把“成功”分成四级</h3><table><thead><tr><th>成功级别</th><th>Matter over Thread 示例</th><th>Zigbee 示例</th><th>还不能证明</th></tr></thead><tbody><tr><td>发现成功</td><td>找到 BLE 广播</td><td>看到 Beacon</td><td>已建立安全或网络成员关系</td></tr><tr><td>网络接入成功</td><td>Thread Attach &#x2F; IPv6 可用</td><td>Association + 安全 NWK 通信</td><td>长期应用关系和平台识别完成</td></tr><tr><td>长期信任成功</td><td>NOC、CASE、CommissioningComplete</td><td>BDB 和目标安全流程完成</td><td>状态订阅、Reporting 一定正常</td></tr><tr><td>业务可用</td><td>Read&#x2F;Subscribe&#x2F;Report 正常</td><td>Interview&#x2F;Binding&#x2F;Reporting 正常</td><td>所有异常和长期稳定性都已验证</td></tr></tbody></table><p>这四级比一个模糊的“配网成功”更适合分析真实问题。</p><blockquote><p><strong>到这里证明了什么？</strong></p><p>只有平台成功识别设备并稳定收发业务状态，才能说门磁对用户真正可用。</p></blockquote><h2 id="第-11-章：断线以后，为什么有时自动回来，有时必须重新配网？"><a href="#第-11-章：断线以后，为什么有时自动回来，有时必须重新配网？" class="headerlink" title="第 11 章：断线以后，为什么有时自动回来，有时必须重新配网？"></a>第 11 章：断线以后，为什么有时自动回来，有时必须重新配网？</h2><p>设备离线不等于所有身份和密钥都已丢失。</p><h3 id="Matter-over-Thread"><a href="#Matter-over-Thread" class="headerlink" title="Matter over Thread"></a>Matter over Thread</h3><p>如果设备仍保存 Thread Dataset 和 Fabric 凭据：</p><ul><li>Thread 可以重新选择父节点并 Reattach；</li><li>IPv6 地址或路由位置可能变化；</li><li>Controller 可以重新执行 Operational Discovery；</li><li>CASE 会话可以按需重新建立；</li><li>原有 Fabric 身份不需要因为一次无线掉线重新签发。</li></ul><p>因此：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Thread Reattach ≠ Matter Recommissioning</span><br><span class="line">CASE 重建 ≠ 重新扫码入网</span><br><span class="line">IPv6 地址变化 ≠ Matter Node 身份变化</span><br></pre></td></tr></table></figure><p>只有凭据被清除、Fabric 被移除、网络资料失效或设备恢复出厂等情况，才可能需要重新走完整 commissioning。</p><h3 id="Zigbee"><a href="#Zigbee" class="headerlink" title="Zigbee"></a>Zigbee</h3><p>设备如果保留网络参数和安全材料，可以通过 Rejoin 或恢复父子关系重新接入。Rejoin 与 Factory New 设备的首次 Network Steering 不是同一条路径。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Zigbee Rejoin ≠ 首次 Network Steering</span><br><span class="line">父节点变化 ≠ EUI-64 身份变化</span><br><span class="line">短地址变化 ≠ 换了一台物理设备</span><br></pre></td></tr></table></figure><p>具体 Rejoin 安全条件仍取决于网络和 BDB 策略。</p><h2 id="第-12-章：Matter-这样设计，究竟比-Zigbee-好在哪里？"><a href="#第-12-章：Matter-这样设计，究竟比-Zigbee-好在哪里？" class="headerlink" title="第 12 章：Matter 这样设计，究竟比 Zigbee 好在哪里？"></a>第 12 章：Matter 这样设计，究竟比 Zigbee 好在哪里？</h2><p>不能用“步骤更多”直接推出“协议更安全”，也不能用“步骤更少”直接推出“体验更好”。更公平的比较是看两边选择解决什么问题，以及复杂度放在哪里。</p><h3 id="Matter-over-Thread-的主要设计收益"><a href="#Matter-over-Thread-的主要设计收益" class="headerlink" title="Matter over Thread 的主要设计收益"></a>Matter over Thread 的主要设计收益</h3><ul><li>把低功耗 IP 网络与 Matter 应用身份分开；</li><li>把初始配网秘密与长期运行证书分开；</li><li>定义设备认证和产品身份验证流程；</li><li>使用 Fabric、Node 身份和访问控制管理权限；</li><li>允许同一应用协议运行在 Thread、Wi-Fi 和 Ethernet 等 IP 承载上；</li><li>Thread Border Router 不需要翻译 Matter 应用数据；</li><li>每个阶段都有相对清晰的成功边界。</li></ul><h3 id="Matter-over-Thread-付出的成本"><a href="#Matter-over-Thread-付出的成本" class="headerlink" title="Matter over Thread 付出的成本"></a>Matter over Thread 付出的成本</h3><ul><li>角色、凭据和状态更多；</li><li>需要从 Bluetooth LE 临时通道切换到 Thread&#x2F;IP；</li><li>要处理 PASE、Attestation、证书、CASE 和访问控制；</li><li>Border Router、DNS-SD 或 IPv6 路径问题也会影响 commissioning；</li><li>日志里会出现更多“部分成功”状态。</li></ul><h3 id="经典-Zigbee-架构的主要特点"><a href="#经典-Zigbee-架构的主要特点" class="headerlink" title="经典 Zigbee 架构的主要特点"></a>经典 Zigbee 架构的主要特点</h3><ul><li>网络、安全和应用模型在同一套协议体系中；</li><li>典型网关架构下，首次加入链路比较集中；</li><li>Coordinator、Trust Center 和应用管理经常由同一网关统一提供；</li><li>低功耗 Mesh、Cluster、Binding 和 Reporting 形成成熟体系；</li><li>跨 IP 网络或跨 Matter 生态时，通常由网关或 Bridge 终止两边协议并做应用语义转换。</li></ul><h3 id="Zigbee-的复杂度并没有消失"><a href="#Zigbee-的复杂度并没有消失" class="headerlink" title="Zigbee 的复杂度并没有消失"></a>Zigbee 的复杂度并没有消失</h3><p>Zigbee 用户界面可能只显示“正在搜索设备”，但底层仍可能经历：</p><ul><li>多信道扫描；</li><li>父节点选择；</li><li>Association；</li><li>Trust Center 准入；</li><li>Transport Key；</li><li>Network Key 安装；</li><li>Frame Counter 与 Key Sequence 管理；</li><li>TCLK 相关流程；</li><li>Descriptor 查询；</li><li>Binding 与 Reporting。</li></ul><p>很多复杂度被网关集中处理，不代表它不存在。</p><h2 id="第-13-章：如果把每个-Matter-步骤删掉，会失去什么？"><a href="#第-13-章：如果把每个-Matter-步骤删掉，会失去什么？" class="headerlink" title="第 13 章：如果把每个 Matter 步骤删掉，会失去什么？"></a>第 13 章：如果把每个 Matter 步骤删掉，会失去什么？</h2><table><thead><tr><th>被删掉的步骤</th><th>直接失去的能力</th></tr></thead><tbody><tr><td>Commissioning Window</td><td>难以把用户意图与本次入网尝试绑定</td></tr><tr><td>QR &#x2F; Manual Code</td><td>缺少目标筛选和设备初始秘密</td></tr><tr><td>Bluetooth LE 临时通道</td><td>未加入 Thread 的普通设备难以直接从手机获得网络资料</td></tr><tr><td>PASE</td><td>缺少基于 Setup Passcode 的临时安全会话</td></tr><tr><td>Device Attestation</td><td>难以标准化验证设备认证身份和产品声明</td></tr><tr><td>CSR &#x2F; NOC</td><td>缺少设备独有的 Matter Fabric 运行身份</td></tr><tr><td>Thread Dataset</td><td>设备不知道怎样加入目标 Thread 网络</td></tr><tr><td>Operational Discovery</td><td>Controller 难以找到设备当前正式 IP 地址和端口</td></tr><tr><td>CASE</td><td>缺少基于 Fabric 证书的长期单播安全会话</td></tr><tr><td>CommissioningComplete</td><td>难以安全确认并结束本次配置，Fail-safe 无法正常闭环</td></tr><tr><td>Subscribe</td><td>平台可能无法持续获得门状态变化</td></tr></tbody></table><p>这张表也回答了开篇问题：Matter over Thread 的长流程并不是围绕一个“无线连接”问题反复加步骤，而是连续解决不同问题。</p><h2 id="第-14-章：用两个故障练习检查是否真的看懂"><a href="#第-14-章：用两个故障练习检查是否真的看懂" class="headerlink" title="第 14 章：用两个故障练习检查是否真的看懂"></a>第 14 章：用两个故障练习检查是否真的看懂</h2><h3 id="故障一：Matter-设备已经成为-Thread-Child，但-App-最后超时"><a href="#故障一：Matter-设备已经成为-Thread-Child，但-App-最后超时" class="headerlink" title="故障一：Matter 设备已经成为 Thread Child，但 App 最后超时"></a>故障一：Matter 设备已经成为 Thread Child，但 App 最后超时</h3><p>已经证明：</p><ul><li>设备找到了 Thread 网络；</li><li>Parent-Child 关系已经建立；</li><li>Thread Attach 至少进展到网络层成功附近。</li></ul><p>还要继续检查：</p><ol><li>设备是否发布或代理了运行态发现信息；</li><li>Commissioner 是否完成 Operational Discovery；</li><li>CASE 是否建立；</li><li>CommissioningComplete 是否成功；</li><li>后续 Read、Subscribe 和 Report 是否出现。</li></ol><p>不能因为 Thread Attached 就直接修改应用 Cluster，也不能把超时一概归因于射频。</p><h3 id="故障二：Zigbee-门磁已经获得短地址，但网关没有显示设备"><a href="#故障二：Zigbee-门磁已经获得短地址，但网关没有显示设备" class="headerlink" title="故障二：Zigbee 门磁已经获得短地址，但网关没有显示设备"></a>故障二：Zigbee 门磁已经获得短地址，但网关没有显示设备</h3><p>已经证明：</p><ul><li>Association 至少进展到地址分配；</li><li>设备与父节点之间有基本链路。</li></ul><p>还要继续检查：</p><ol><li>Transport Key 是否到达接收端；</li><li>设备是否成功验证并安装 Network Key；</li><li>是否开始受保护的 NWK 通信；</li><li>BDB 和目标 TCLK 流程是否完成；</li><li>Device Announcement 和 Descriptor 查询是否成功；</li><li>Reporting 是否正确配置。</li></ol><p>不能把 MAC ACK、Association Response 或短地址当成完整业务成功。</p><h2 id="一张最终时间线"><a href="#一张最终时间线" class="headerlink" title="一张最终时间线"></a>一张最终时间线</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">Matter over Thread</span><br><span class="line"></span><br><span class="line">用户打开配网</span><br><span class="line">  -&gt; 扫码获得引导信息</span><br><span class="line">  -&gt; 发现并连接 BLE 设备</span><br><span class="line">  -&gt; PASE 临时安全会话</span><br><span class="line">  -&gt; Fail-safe 与基础配置</span><br><span class="line">  -&gt; Device Attestation</span><br><span class="line">  -&gt; CSR / NOC / Fabric 身份</span><br><span class="line">  -&gt; 配置 Thread Dataset</span><br><span class="line">  -&gt; Thread Attach</span><br><span class="line">  -&gt; Operational Discovery</span><br><span class="line">  -&gt; CASE 正式安全会话</span><br><span class="line">  -&gt; CommissioningComplete</span><br><span class="line">  -&gt; 读取设备能力并建立 Subscribe</span><br><span class="line">  -&gt; 门磁业务可用</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">经典 Zigbee 集中式首次加入</span><br><span class="line"></span><br><span class="line">网关打开 Permit Join</span><br><span class="line">  -&gt; 设备启动 Network Steering</span><br><span class="line">  -&gt; 扫描信道与 Beacon</span><br><span class="line">  -&gt; 选择网络和父节点</span><br><span class="line">  -&gt; Association</span><br><span class="line">  -&gt; 获得短地址</span><br><span class="line">  -&gt; Trust Center 安全准入</span><br><span class="line">  -&gt; 接收并安装 Network Key</span><br><span class="line">  -&gt; 受保护的 Zigbee 通信</span><br><span class="line">  -&gt; Device Announcement</span><br><span class="line">  -&gt; TCLK / BDB 相应流程</span><br><span class="line">  -&gt; Descriptor / Cluster 识别</span><br><span class="line">  -&gt; Binding / Reporting</span><br><span class="line">  -&gt; 门磁业务可用</span><br></pre></td></tr></table></figure><h2 id="最后只记住三句话"><a href="#最后只记住三句话" class="headerlink" title="最后只记住三句话"></a>最后只记住三句话</h2><blockquote><p>Thread 解决设备怎样接入低功耗 IPv6 网络。</p></blockquote><blockquote><p>Matter 解决设备是谁、属于哪个信任域、谁能控制它，以及怎样表达设备能力。</p></blockquote><blockquote><p>Zigbee 使用另一套更集中的网络、安全和应用体系完成相似的产品目标。</p></blockquote><p>Matter over Thread 不是简单地把 Zigbee 的一次入网拆成更多消息。它把网络接入、初始秘密、产品身份、长期 Fabric 身份、正式安全会话和应用权限分别建模。</p><p>它的优势来自这种拆分，它的复杂度也来自这种拆分。</p><h2 id="术语速查"><a href="#术语速查" class="headerlink" title="术语速查"></a>术语速查</h2><table><thead><tr><th>术语</th><th>所属体系</th><th>一句话解释</th></tr></thead><tbody><tr><td>Commissioning</td><td>Matter</td><td>把设备安全登记进 Fabric 并配置运行网络的完整过程</td></tr><tr><td>Commissioner</td><td>Matter</td><td>负责办理 commissioning 的一方</td></tr><tr><td>Commissionee</td><td>Matter</td><td>正在被 commissioning 的设备</td></tr><tr><td>Fabric</td><td>Matter</td><td>共享运行信任根和管理关系的 Matter 信任域</td></tr><tr><td>PASE</td><td>Matter</td><td>基于 Setup Passcode 的初始安全会话</td></tr><tr><td>Device Attestation</td><td>Matter</td><td>验证设备认证身份、签名和产品声明的流程</td></tr><tr><td>DAC &#x2F; PAI &#x2F; PAA</td><td>Matter</td><td>从设备证书到信任根的认证链角色</td></tr><tr><td>CSR</td><td>Matter</td><td>设备为运行证书提交的签名请求</td></tr><tr><td>NOC</td><td>Matter</td><td>Matter Node 在某个 Fabric 中的运行证书</td></tr><tr><td>CASE</td><td>Matter</td><td>基于 Fabric 运行凭据的正式单播安全会话</td></tr><tr><td>Operational Discovery</td><td>Matter</td><td>在正式 IP 网络中解析已入网 Node 的地址和端口</td></tr><tr><td>Active Operational Dataset</td><td>Thread</td><td>描述 Thread 网络参数和安全材料的配置集合</td></tr><tr><td>MLE Attach</td><td>Thread</td><td>发现 Parent 并建立 Thread 邻居关系的过程</td></tr><tr><td>Border Router</td><td>Thread</td><td>在 Thread 与相邻 IP 网络之间转发数据</td></tr><tr><td>Permit Join</td><td>Zigbee</td><td>网络暂时允许新设备申请加入</td></tr><tr><td>Network Steering</td><td>Zigbee</td><td>设备寻找并尝试加入合适网络的 BDB 方法</td></tr><tr><td>Association</td><td>IEEE 802.15.4 &#x2F; Zigbee 路径</td><td>建立网络成员和父子关系的 MAC 服务</td></tr><tr><td>Network Key</td><td>Zigbee</td><td>保护 Zigbee NWK 层通信的网络共享密钥</td></tr><tr><td>TCLK</td><td>Zigbee</td><td>设备与 Trust Center 之间的 Link Key</td></tr><tr><td>Device Announcement</td><td>Zigbee</td><td>设备向网络公告地址映射等信息</td></tr><tr><td>Reporting</td><td>Zigbee</td><td>按条件或周期报告属性变化</td></tr></tbody></table><h2 id="继续阅读与资料来源"><a href="#继续阅读与资料来源" class="headerlink" title="继续阅读与资料来源"></a>继续阅读与资料来源</h2><p>站内延伸：</p><ul><li><a href="/posts/matter-foundations/">Matter 基础概念：Node、Fabric、Endpoint 与安全会话</a></li><li><a href="/posts/thread-foundations/">Thread 基础概念：IPv6 Mesh、设备角色与 Border Router</a></li><li><a href="/posts/matter-zigbee-concept-mapping/">Matter 与 Zigbee 关系映射：相似名词不等于相同协议</a></li><li><a href="/posts/zigbee-network-joining-flow/">Zigbee 入网流程：从 Network Steering 到可用设备</a></li><li><a href="/posts/zigbee-security-key-scope/">Zigbee 各类 Key 的作用范围</a></li></ul><p>公开技术资料：</p><ul><li><a href="https://csa-iot.org/developer-resource/specifications-download-request/">CSA 规范下载入口</a></li><li><a href="https://project-chip.github.io/connectedhomeip-doc/development_controllers/chip-tool/chip_tool_guide.html">Matter 官方开源 SDK：CHIP Tool Commissioning Guide</a></li><li><a href="https://project-chip.github.io/connectedhomeip-doc/guides/access-control-guide.html">Matter SDK Access Control Guide</a></li><li><a href="https://openthread.io/guides/thread-primer/network-discovery">OpenThread：Network Discovery and Formation</a></li><li><a href="https://openthread.io/guides/thread-primer/node-roles-and-types">OpenThread：Node Roles and Types</a></li><li><a href="https://threadgroup.org/Newsroom/Blog/what-is-a-thread-border-router-and-how-is-it-different-from-a-hub-or-a-bridge">Thread Group：Border Router 的职责</a></li><li><a href="https://csa-iot.org/wp-content/uploads/2023/04/05-3474-23-csg-zigbee-specification-compressed.pdf">CSA Zigbee Specification</a></li></ul><p>本文描述的是便于理解的高层主线，不替代目标版本的 Matter Core、Thread、Zigbee Core、BDB 与生态实现要求。认证、量产和故障定责还应结合目标版本规范、设备日志、Controller 或网关日志与抓包证据。</p>]]>
    </content>
    <id>https://onium.top/posts/matter-over-thread-zigbee-commissioning-comparison/</id>
    <link href="https://onium.top/posts/matter-over-thread-zigbee-commissioning-comparison/"/>
    <published>2026-07-30T02:00:00.000Z</published>
    <summary>
      <![CDATA[<p>Zigbee 设备打开允许加入、搜索网络、获得密钥，似乎就能完成入网。Matter over Thread 为什么还要扫码、连接 Bluetooth LE、建立临时安全通道、验证设备证书、写入长期身份、加入 Thread，再切换到 IP 网络重新连接？</p>
<p>这些步骤是在把简单问题复杂化，还是在解决不同的问题？</p>]]>
    </summary>
    <title>Matter over Thread 入网为什么这么复杂？与 Zigbee 一步一步对照看懂</title>
    <updated>2026-07-30T02:54:09.518Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="生态适配" scheme="https://onium.top/categories/%E7%94%9F%E6%80%81%E9%80%82%E9%85%8D/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="SmartThings" scheme="https://onium.top/tags/smartthings/"/>
    <category term="Edge Driver" scheme="https://onium.top/tags/edge-driver/"/>
    <category term="Lua" scheme="https://onium.top/tags/lua/"/>
    <category term="CLI" scheme="https://onium.top/tags/cli/"/>
    <content>
      <![CDATA[<p>写完 SmartThings Edge Driver 只是第一步。要让测试者通过一个链接安装 Driver，还要完成云端上传、Channel 版本绑定、Hub 注册、Driver 安装和邀请创建。这些动作处在不同层级，任何一步“成功”都不能替代下一步验证。</p><span id="more"></span><h2 id="先理解完整链路"><a href="#先理解完整链路" class="headerlink" title="先理解完整链路"></a>先理解完整链路</h2><p>一条可复用的发布链是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">本地源码</span><br><span class="line">  -&gt; fingerprint / profile / handler 静态检查</span><br><span class="line">  -&gt; 本地 build-only 打包</span><br><span class="line">  -&gt; 上传 Driver，产生 Driver ID 与 Version</span><br><span class="line">  -&gt; 创建或选择 Driver Channel</span><br><span class="line">  -&gt; 把指定 Driver Version 分配到 Channel</span><br><span class="line">  -&gt; 将测试 Hub 注册到 Channel</span><br><span class="line">  -&gt; 从 Channel 安装 Driver 到 Hub</span><br><span class="line">  -&gt; 创建 Channel Invitation</span><br><span class="line">  -&gt; 通过真实设备完成运行验证</span><br></pre></td></tr></table></figure><p>其中有三个容易混淆的对象：</p><table><thead><tr><th>对象</th><th>作用</th><th>是否秘密</th></tr></thead><tbody><tr><td>PAT &#x2F; OAuth Token</td><td>允许 CLI 调用 SmartThings API</td><td>是</td></tr><tr><td>Driver Channel</td><td>固定并分发一组 Driver 版本</td><td>通常不公开其管理信息</td></tr><tr><td>Invitation URL</td><td>邀请其他账号加入 Channel</td><td>按分享范围管理</td></tr></tbody></table><p>邀请链接不是登录 Token。创建邀请后，不需要把 PAT 一起发给测试者；PAT 过期也不等于已经创建的邀请立即失效。</p><h2 id="CLI-认证：PAT-适合临时操作"><a href="#CLI-认证：PAT-适合临时操作" class="headerlink" title="CLI 认证：PAT 适合临时操作"></a>CLI 认证：PAT 适合临时操作</h2><p>SmartThings CLI 默认支持浏览器 OAuth 登录，也支持使用 Personal Access Token。当前新建 PAT 的有效期是 24 小时，不能设置成永久 Token。</p><p>在临时测试或无图形界面的开发机上，可以把 PAT 放进 CLI 配置：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">default:</span></span><br><span class="line">  <span class="attr">token:</span> <span class="string">&quot;&lt;YOUR_PAT&gt;&quot;</span></span><br></pre></td></tr></table></figure><p>配置文件通常位于：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~/.config/@smartthings/cli/config.yaml</span><br></pre></td></tr></table></figure><p>限制文件权限：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 600 ~/.config/@smartthings/cli/config.yaml</span><br></pre></td></tr></table></figure><p>不要把真实 Token 写进 Git、脚本、截图或文章，也尽量不要通过 <code>--token</code> 直接放在命令行中，以免进入 Shell history。出现 <code>401 Unauthorized</code> 时，先检查 Token 是否已过期，以及创建 PAT 时是否选择了所需 Scope。管理 Driver Channel 时，至少要注意官方文档要求的 Channel 读写权限。</p><p>如果是长期运行的服务集成，应使用 OAuth 2.0 和刷新机制，而不是定期手工更换 PAT。对于偶尔执行一次的 CLI 发布任务，短期 PAT 更简单，但要接受每天重新签发的限制。</p><h2 id="设备身份：允许别名，但不要放宽匹配"><a href="#设备身份：允许别名，但不要放宽匹配" class="headerlink" title="设备身份：允许别名，但不要放宽匹配"></a>设备身份：允许别名，但不要放宽匹配</h2><p>实际项目中，同一类硬件可能因固件批次、销售渠道或身份迁移而报告不同 Model。此时可以让多个精确 fingerprint 指向同一个 Profile：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">zigbeeManufacturer:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">&quot;example/motion-a&quot;</span></span><br><span class="line">    <span class="attr">manufacturer:</span> <span class="string">&quot;Example&quot;</span></span><br><span class="line">    <span class="attr">model:</span> <span class="string">&quot;MOTION-A&quot;</span></span><br><span class="line">    <span class="attr">deviceProfileName:</span> <span class="string">&quot;motion-light-battery&quot;</span></span><br><span class="line">    <span class="attr">deviceLabel:</span> <span class="string">&quot;Motion sensor&quot;</span></span><br><span class="line"></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">&quot;example/motion-b&quot;</span></span><br><span class="line">    <span class="attr">manufacturer:</span> <span class="string">&quot;Example&quot;</span></span><br><span class="line">    <span class="attr">model:</span> <span class="string">&quot;MOTION-B&quot;</span></span><br><span class="line">    <span class="attr">deviceProfileName:</span> <span class="string">&quot;motion-light-battery&quot;</span></span><br><span class="line">    <span class="attr">deviceLabel:</span> <span class="string">&quot;Motion sensor&quot;</span></span><br></pre></td></tr></table></figure><p>这表示两个身份共享同一组平台能力，不表示它们的 Zigbee 行为必然完全相同。至少要逐项比较：</p><ul><li>Endpoint、Device ID 与 Server&#x2F;Client Cluster；</li><li>Attribute 类型、单位、倍率和无效值；</li><li>上报方式、Reporting 配置与休眠行为；</li><li>厂商自定义 Cluster、Attribute 和 Command；</li><li>首次加入、rejoin、重启和恢复出厂行为。</li></ul><p>Sub-driver 的 <code>can_handle</code> 也要覆盖同一组身份，并同时检查 Manufacturer 和 Model：</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> supported_models = &#123;</span><br><span class="line">  [<span class="string">&quot;MOTION-A&quot;</span>] = <span class="literal">true</span>,</span><br><span class="line">  [<span class="string">&quot;MOTION-B&quot;</span>] = <span class="literal">true</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> <span class="title">can_handle</span><span class="params">(_, _, device)</span></span></span><br><span class="line">  <span class="keyword">return</span> device:get_manufacturer() == <span class="string">&quot;Example&quot;</span></span><br><span class="line">    <span class="keyword">and</span> supported_models[device:get_model()] == <span class="literal">true</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>只检查 Model、只检查 Manufacturer，或让 fingerprint 与 <code>can_handle</code> 使用不同的身份集合，都会造成“选中了 Profile，却没有进入预期 Handler”的隐蔽故障。</p><h2 id="Profile-只声明真实支持的能力"><a href="#Profile-只声明真实支持的能力" class="headerlink" title="Profile 只声明真实支持的能力"></a>Profile 只声明真实支持的能力</h2><p>一个运动传感器 Profile 可能包含：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">motion-light-battery</span></span><br><span class="line"><span class="attr">components:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">main</span></span><br><span class="line">    <span class="attr">capabilities:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">motionSensor</span></span><br><span class="line">        <span class="attr">version:</span> <span class="number">1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">illuminanceMeasurement</span></span><br><span class="line">        <span class="attr">version:</span> <span class="number">1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">battery</span></span><br><span class="line">        <span class="attr">version:</span> <span class="number">1</span></span><br><span class="line">    <span class="attr">categories:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">MotionSensor</span></span><br></pre></td></tr></table></figure><p>如果 Driver 还支持检测保持时间、照度补偿等参数，可以通过 Preference 或自定义 Capability 暴露，但必须确认：</p><ol><li>Driver 能把 App 命令正确转换成 Zigbee Write 或 Command；</li><li>设备会接受该值；</li><li>Read Back 或后续 Report 能校正平台状态；</li><li>参数范围和单位与固件一致。</li></ol><p>UI 中出现一个字段，只证明 Profile 被平台接受，不证明设备端功能已经闭环。</p><h2 id="本地门禁：先打包，不上传"><a href="#本地门禁：先打包，不上传" class="headerlink" title="本地门禁：先打包，不上传"></a>本地门禁：先打包，不上传</h2><p>在执行任何云端写操作前，先完成本地检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">luac -p src/init.lua</span><br><span class="line">luac -p src/sub_drivers/example/init.lua</span><br></pre></td></tr></table></figure><p>再检查 YAML、JSON、fingerprint、Profile 和 Handler 的一致性。最关键的交叉关系包括：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">fingerprint.deviceProfileName -&gt; profiles/&lt;name&gt;.yml</span><br><span class="line">fingerprint Manufacturer/Model -&gt; can_handle 支持集合</span><br><span class="line">profile capability -&gt; 默认 Handler 或自定义 Handler</span><br><span class="line">config.yml permissions -&gt; 实际使用的 Zigbee Cluster</span><br></pre></td></tr></table></figure><p>SmartThings CLI 的无上传构建命令是：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:drivers:package \</span><br><span class="line">  --build-only /tmp/example-driver.zip \</span><br><span class="line">  &lt;driver-directory&gt;</span><br></pre></td></tr></table></figure><p>注意命令中的 <code>drivers</code> 是复数。<code>--build-only</code> 只生成 Zip，用于验证目录和包结构，不会创建云端 Driver 版本。</p><p>本地打包通过仍然不能证明：</p><ul><li>fingerprint 能匹配真实设备；</li><li>Hub 上能加载 Driver；</li><li>Zigbee 上报能转成正确 Capability event；</li><li>App 下发能到达设备；</li><li>rejoin、重启和低功耗场景正常。</li></ul><h2 id="上传-Driver"><a href="#上传-Driver" class="headerlink" title="上传 Driver"></a>上传 Driver</h2><p>确认本地门禁通过后，再执行上传：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:drivers:package --json &lt;driver-directory&gt;</span><br></pre></td></tr></table></figure><p>保存返回结果中的：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Driver ID</span><br><span class="line">Driver Version</span><br></pre></td></tr></table></figure><p>同一个 Driver 每次重新打包上传都会产生新 Version。后续给 Channel 分配时要使用这次返回的准确版本，不要只记 Driver ID。</p><p>执行云端写操作前，建议先列出现有资源：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:drivers --json</span><br><span class="line">smartthings edge:channels --json</span><br><span class="line">smartthings devices --<span class="built_in">type</span>=HUB --json</span><br></pre></td></tr></table></figure><p>这样可以避免重复创建 Channel，也能确认当前账号、区域和 Hub 是否正确。</p><h2 id="创建-Channel-并绑定版本"><a href="#创建-Channel-并绑定版本" class="headerlink" title="创建 Channel 并绑定版本"></a>创建 Channel 并绑定版本</h2><p>第一次发布时创建 Driver Channel：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:channels:create</span><br></pre></td></tr></table></figure><p>CLI 会交互式询问名称、描述和服务条款链接。也可以先准备 JSON&#x2F;YAML，再使用 <code>--input</code>。</p><p>将刚上传的指定版本分配到 Channel：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:channels:assign \</span><br><span class="line">  &lt;DRIVER_ID&gt; \</span><br><span class="line">  &lt;DRIVER_VERSION&gt; \</span><br><span class="line">  --channel &lt;CHANNEL_ID&gt;</span><br></pre></td></tr></table></figure><p>Channel 锁定的是一个具体 Driver Version。以后上传新版本，不会自动替换 Channel 中的旧版本，也不会自动更新 Hub 上已安装的版本。</p><p>如果创建 Channel 时遇到 <code>502</code> 或响应体为空，不要立即连续重试。先重新查询：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:channels --json</span><br></pre></td></tr></table></figure><p>确认服务端是否已经创建成功，再决定是否重试，避免产生重复 Channel。</p><h2 id="Enroll-Hub-并安装-Driver"><a href="#Enroll-Hub-并安装-Driver" class="headerlink" title="Enroll Hub 并安装 Driver"></a>Enroll Hub 并安装 Driver</h2><p>先把自己的测试 Hub 注册到 Channel：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:channels:enroll \</span><br><span class="line">  &lt;HUB_ID&gt; \</span><br><span class="line">  --channel &lt;CHANNEL_ID&gt;</span><br></pre></td></tr></table></figure><p>然后从该 Channel 安装 Driver：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:drivers:install \</span><br><span class="line">  &lt;DRIVER_ID&gt; \</span><br><span class="line">  --hub &lt;HUB_ID&gt; \</span><br><span class="line">  --channel &lt;CHANNEL_ID&gt;</span><br></pre></td></tr></table></figure><p>这两步解决的问题不同：</p><ul><li><code>enroll</code>：让 Hub 能看到 Channel；</li><li><code>install</code>：把 Channel 中的某个 Driver 安装到 Hub。</li></ul><p>只有 Channel 中存在正确版本、Hub 已注册、Driver 已安装，真实设备加入时才有机会匹配该 Driver。</p><p>更新版本时，可以重新 Assign 并 Install，也可以使用官方提供的组合方式：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:drivers:package \</span><br><span class="line">  &lt;driver-directory&gt; \</span><br><span class="line">  --install \</span><br><span class="line">  --channel &lt;CHANNEL_ID&gt; \</span><br><span class="line">  --hub &lt;HUB_ID&gt;</span><br></pre></td></tr></table></figure><p>组合命令更方便，拆分命令则更适合首次发布和故障定位，因为每一步的输入与结果更清楚。</p><h2 id="生成并核对邀请链接"><a href="#生成并核对邀请链接" class="headerlink" title="生成并核对邀请链接"></a>生成并核对邀请链接</h2><p>为指定 Channel 创建邀请：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:channels:invites:create \</span><br><span class="line">  --channel &lt;CHANNEL_ID&gt;</span><br></pre></td></tr></table></figure><p>CLI 会根据交互选项创建 Invitation，并返回分享 URL。创建后再查询一次：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:channels:invites \</span><br><span class="line">  --channel &lt;CHANNEL_ID&gt;</span><br></pre></td></tr></table></figure><p>核对邀请是否存在、状态是否符合预期、URL 是否对应目标 Channel。不要只以“命令没有报错”作为成功证据。</p><p>收到链接的测试者通常需要：</p><ol><li>打开 Invitation URL 并登录 Samsung Account；</li><li>接受邀请；</li><li>选择自己的 Hub 加入 Channel；</li><li>在可用 Driver 中选择并安装；</li><li>在 SmartThings App 中重新添加或迁移目标设备。</li></ol><p>第三方 Edge Driver 不等于 SmartThings 官方审核或认证 Driver。邀请页可访问、Driver 可安装，也不能替代真实设备验证和正式生态认证。</p><h2 id="验证结果必须分层"><a href="#验证结果必须分层" class="headerlink" title="验证结果必须分层"></a>验证结果必须分层</h2><p>建议用下面的矩阵记录结果：</p><table><thead><tr><th>层级</th><th>最小证据</th><th>能证明什么</th></tr></thead><tbody><tr><td>静态</td><td>Lua、YAML、JSON 检查通过</td><td>文件可解析、引用基本一致</td></tr><tr><td>本地构建</td><td><code>--build-only</code> 成功生成 Zip</td><td>Driver 包结构可构建</td></tr><tr><td>云端上传</td><td>返回 Driver ID 与 Version</td><td>云端接受该版本</td></tr><tr><td>Channel</td><td>查询到准确 Driver Version</td><td>目标版本已进入分发通道</td></tr><tr><td>Hub</td><td>安装列表中存在 Driver</td><td>Driver 已部署到目标 Hub</td></tr><tr><td>匹配</td><td>Live log 显示目标设备选中 Driver</td><td>fingerprint 与 Handler 生效</td></tr><tr><td>上行</td><td>运动、照度、电量事件正确</td><td>Zigbee 到 Capability 路径成立</td></tr><tr><td>下行</td><td>参数写入、响应与 Read Back 正确</td><td>Capability 到 Zigbee 路径成立</td></tr><tr><td>稳定性</td><td>重启、rejoin、休眠恢复通过</td><td>生命周期和低功耗行为可用</td></tr></tbody></table><p>查看 Hub 运行日志可使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:drivers:logcat --hub-address=&lt;HUB_IP&gt;</span><br></pre></td></tr></table></figure><p>日志公开前要删除设备 EUI、Hub 地址、Location、账号信息、Channel&#x2F;Driver UUID 和任何网络密钥。</p><h2 id="发布前隐私清单"><a href="#发布前隐私清单" class="headerlink" title="发布前隐私清单"></a>发布前隐私清单</h2><p>提交 Driver 或技术文章前，至少搜索：</p><ul><li>PAT、OAuth Client Secret、Refresh Token；</li><li>Invitation URL 与短码；</li><li>Hub、Location、Channel、Driver、Device UUID；</li><li>设备 EUI、Network Key、Install Code；</li><li>内部仓库地址、本机绝对路径和公司环境名称；</li><li>未公开产品型号、固件版本和测试记录。</li></ul><p>示例应使用 <code>&lt;CHANNEL_ID&gt;</code>、<code>&lt;DRIVER_ID&gt;</code>、<code>&lt;HUB_ID&gt;</code> 等占位符。邀请链接虽然不是账号 Token，但获得链接的人可能因此访问测试 Channel，仍应按预期受众控制传播。</p><h2 id="最后形成可重复的发布节奏"><a href="#最后形成可重复的发布节奏" class="headerlink" title="最后形成可重复的发布节奏"></a>最后形成可重复的发布节奏</h2><p>一次稳妥的迭代可以压缩为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">精确身份匹配</span><br><span class="line">  -&gt; 本地静态检查</span><br><span class="line">  -&gt; build-only</span><br><span class="line">  -&gt; 上传新 Version</span><br><span class="line">  -&gt; Channel 重新 Assign</span><br><span class="line">  -&gt; Hub 重新 Install</span><br><span class="line">  -&gt; Live log + 真实设备回归</span><br><span class="line">  -&gt; 最后才分享 Invitation URL</span><br></pre></td></tr></table></figure><p>把每一步的 ID、Version、命令结果和验证结论保存在私有发布记录中；公开文章只保留方法、占位符和经过脱敏的错误现象。这样既能让发布流程可追溯，也不会把认证凭证和测试环境暴露出去。</p><p>官方资料：</p><ul><li><a href="https://developer.smartthings.com/docs/sdks/cli">SmartThings CLI 与认证</a></li><li><a href="https://developer.smartthings.com/docs/devices/hub-connected/driver-channels">Driver Channels</a></li><li><a href="https://developer.smartthings.com/docs/devices/hub-connected/enroll-in-a-shared-channel">接受共享 Channel 并安装 Driver</a></li><li><a href="https://developer.smartthings.com/docs/getting-started/authorization-and-permissions">Authorization and Permissions</a></li><li><a href="https://developer.smartthings.com/docs/devices/hub-connected/driver-components-and-structure">Edge Driver 结构</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/smartthings-edge-driver-channel-invitation-workflow/</id>
    <link href="https://onium.top/posts/smartthings-edge-driver-channel-invitation-workflow/"/>
    <published>2026-07-30T01:30:00.000Z</published>
    <summary>
      <![CDATA[<p>写完 SmartThings Edge Driver 只是第一步。要让测试者通过一个链接安装 Driver，还要完成云端上传、Channel 版本绑定、Hub 注册、Driver 安装和邀请创建。这些动作处在不同层级，任何一步“成功”都不能替代下一步验证。</p>]]>
    </summary>
    <title>SmartThings Edge Driver 发布实战：从本地打包到 Channel 邀请链接</title>
    <updated>2026-07-30T01:39:23.355Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="优化实践" scheme="https://onium.top/categories/%E4%BC%98%E5%8C%96%E5%AE%9E%E8%B7%B5/"/>
    <category term="低功耗" scheme="https://onium.top/tags/%E4%BD%8E%E5%8A%9F%E8%80%97/"/>
    <category term="I2C" scheme="https://onium.top/tags/i2c/"/>
    <category term="传感器" scheme="https://onium.top/tags/%E4%BC%A0%E6%84%9F%E5%99%A8/"/>
    <category term="状态机" scheme="https://onium.top/tags/%E7%8A%B6%E6%80%81%E6%9C%BA/"/>
    <content>
      <![CDATA[<p>在电池供电设备里，环境光传感器通常只需要偶尔提供一个 lux 值。此时“传感器带 IRQ”并不代表 IRQ 一定比定时读取省电。真正决定功耗的是：等待 IRQ 时传感器处于什么模式、转换期间 MCU 能否休眠，以及业务究竟需要周期数据还是实时阈值事件。</p><span id="more"></span><h2 id="先确认-IRQ-的真实语义"><a href="#先确认-IRQ-的真实语义" class="headerlink" title="先确认 IRQ 的真实语义"></a>先确认 IRQ 的真实语义</h2><p>环境光传感器常见的 IRQ 至少有两种：</p><ul><li><strong>Data Ready IRQ</strong>：一次转换完成后通知 MCU 读取结果；</li><li><strong>Threshold IRQ</strong>：光照超过高阈值或低于低阈值时通知 MCU。</li></ul><p>两者看起来都是一根中断线，功耗含义却完全不同。</p><p>Data Ready IRQ 如果能配合 single-shot 使用，传感器完成一次转换后可能自动回到 Standby，适合低功耗周期采集。Threshold IRQ 往往要求传感器保持连续测量；MCU 虽然可以睡眠，传感器本身却持续消耗 Active 电流。</p><p>因此，决定是否使用 IRQ 前应先回答：</p><ol><li>IRQ 是转换完成中断，还是阈值中断？</li><li>IRQ 开启后，传感器能否自动回到 Standby？</li><li>传感器等待 IRQ 时的典型和最大电流是多少？</li><li>业务能接受多大的光照变化检测延迟？</li></ol><p>如果数据手册只描述“Active 模式下设置上下阈值并等待中断”，它通常不是低功耗 single-shot 完成中断。</p><h2 id="常见的四类设计"><a href="#常见的四类设计" class="headerlink" title="常见的四类设计"></a>常见的四类设计</h2><h3 id="Single-shot-或-Forced-Mode"><a href="#Single-shot-或-Forced-Mode" class="headerlink" title="Single-shot 或 Forced Mode"></a>Single-shot 或 Forced Mode</h3><p>主机发起一次转换，传感器完成后自动回到低功耗模式。MCU 可以通过定时器或 Data Ready IRQ 回收结果：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">MCU 启动转换</span><br><span class="line">  -&gt; MCU 休眠</span><br><span class="line">  -&gt; 转换完成</span><br><span class="line">  -&gt; 定时器或 Data Ready 唤醒</span><br><span class="line">  -&gt; 读取结果</span><br><span class="line">  -&gt; 传感器已回到 Standby</span><br></pre></td></tr></table></figure><p>这是周期采集最理想的模式，因为不需要 MCU 额外发命令关闭传感器，也不容易因错误路径遗漏休眠动作。</p><h3 id="超低功耗自主阈值监测"><a href="#超低功耗自主阈值监测" class="headerlink" title="超低功耗自主阈值监测"></a>超低功耗自主阈值监测</h3><p>部分器件有独立的低功耗比较器或专用监测引擎。它可以用较低电流持续判断阈值，只在环境发生明显变化时拉起 IRQ。</p><p>这种方案适合“平时不关心具体 lux，只在由亮变暗时唤醒”的产品，但必须确认数据手册给出的电流属于低功耗监测引擎，而不是普通连续测量模式。</p><h3 id="MCU-定时按需采样"><a href="#MCU-定时按需采样" class="headerlink" title="MCU 定时按需采样"></a>MCU 定时按需采样</h3><p>如果器件只有 Standby 和连续 Active，没有 single-shot 自动回休眠能力，常见做法是由 MCU 把一次连续模式裁剪成一次采样：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">传感器保持 Standby</span><br><span class="line">  -&gt; 软件定时器到期</span><br><span class="line">  -&gt; MCU 设置 Active</span><br><span class="line">  -&gt; MCU 等待转换，条件允许时再次休眠</span><br><span class="line">  -&gt; 检查 Data Valid / New Data</span><br><span class="line">  -&gt; 读取结果</span><br><span class="line">  -&gt; 设置 Standby</span><br></pre></td></tr></table></figure><p>这种设计需要状态机保证任何成功、超时或 I2C 错误路径最终都能让传感器回到 Standby，但其平均电流通常远低于长期连续 Active。</p><h3 id="连续测量加阈值-IRQ"><a href="#连续测量加阈值-IRQ" class="headerlink" title="连续测量加阈值 IRQ"></a>连续测量加阈值 IRQ</h3><p>如果产品必须在较短时间内发现明暗变化，连续模式可能无法避免。此时可以：</p><ul><li>使用业务可接受的最长 Measurement Rate；</li><li>设置高低阈值迟滞，避免在临界点反复触发；</li><li>使用 persistence，要求连续多次越界后才中断；</li><li>MCU 被唤醒后批量处理必要工作，再尽快睡眠。</li></ul><p>这是用功耗换取响应速度，不应包装成单纯的“IRQ 低功耗优化”。</p><h2 id="用占空比估算方向"><a href="#用占空比估算方向" class="headerlink" title="用占空比估算方向"></a>用占空比估算方向</h2><p>假设某颗环境光传感器的参数为：</p><ul><li>Active 电流：266 µA；</li><li>Standby 电流：5 µA；</li><li>每 5 秒采集一次；</li><li>每次从唤醒到读取完成需要 25 ms。</li></ul><p>只考虑传感器自身，平均电流约为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">(266 µA × 25 ms + 5 µA × 4975 ms) / 5000 ms</span><br><span class="line">≈ 6.3 µA</span><br></pre></td></tr></table></figure><p>如果异常情况下等待和重试使 Active 时间增加到 55 ms：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">(266 µA × 55 ms + 5 µA × 4945 ms) / 5000 ms</span><br><span class="line">≈ 7.9 µA</span><br></pre></td></tr></table></figure><p>而长期连续 Active 可能仍是数百微安量级。这个简单估算足以判断架构方向，但不能代替测量：</p><ul><li>手册电流可能只对应某组 Integration Time 和 Measurement Rate；</li><li>Active 内部可能包含测量和 idle，平均电流未必能线性外推；</li><li>MCU、I2C 上拉、稳压器和无线唤醒也会影响整机结果；</li><li>Standby 电流应同时关注典型值、最大值和温度范围。</li></ul><h2 id="优先优化采样策略，而不是一两毫秒"><a href="#优先优化采样策略，而不是一两毫秒" class="headerlink" title="优先优化采样策略，而不是一两毫秒"></a>优先优化采样策略，而不是一两毫秒</h2><p>低功耗优化最容易陷入“把等待时间减少 2 ms”的局部问题。对于几秒甚至几十秒才采一次的数据，减少采样次数通常更有效。</p><h3 id="合并周期请求和事件请求"><a href="#合并周期请求和事件请求" class="headerlink" title="合并周期请求和事件请求"></a>合并周期请求和事件请求</h3><p>设备可能同时有固定周期采样和外部事件触发采样。如果事件刚好发生在周期采样之后，重复启动一次转换没有必要。</p><p>可以维护：</p><ul><li>最近一次有效样本的时间；</li><li>当前是否正在采样；</li><li>哪些业务正在等待本次结果；</li><li>是否还存在必须重新采样的 pending 请求。</li></ul><p>如果样本足够新就直接复用；如果采样正在进行，就让新的使用者等待当前结果，而不是再次启动传感器。</p><h3 id="使用自适应采样周期"><a href="#使用自适应采样周期" class="headerlink" title="使用自适应采样周期"></a>使用自适应采样周期</h3><p>固定 5 秒并不总是合理。更常见的策略是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">环境稳定、无事件</span><br><span class="line">  -&gt; 30 至 60 秒慢速采样</span><br><span class="line"></span><br><span class="line">检测到人体或其他业务事件</span><br><span class="line">  -&gt; 立即采样一次</span><br><span class="line"></span><br><span class="line">光照接近业务判断阈值</span><br><span class="line">  -&gt; 短时间提高采样频率</span><br><span class="line"></span><br><span class="line">环境重新稳定</span><br><span class="line">  -&gt; 退回慢速周期</span><br></pre></td></tr></table></figure><p>如果业务只需要“事件发生时的光照”，甚至可以采用事件触发采样加慢速健康检查，而不是永久维持高频周期采样。</p><h3 id="对齐已有唤醒窗口"><a href="#对齐已有唤醒窗口" class="headerlink" title="对齐已有唤醒窗口"></a>对齐已有唤醒窗口</h3><p>传感器采样可以尽量对齐：</p><ul><li>外部 GPIO 或 PIR 唤醒；</li><li>无线设备的 poll；</li><li>电池测量；</li><li>其他周期维护任务。</li></ul><p>这样不仅降低传感器占空比，还能减少 MCU 从 retention 或 deep sleep 独立唤醒的次数。</p><h2 id="采样频率和上报频率要解耦"><a href="#采样频率和上报频率要解耦" class="headerlink" title="采样频率和上报频率要解耦"></a>采样频率和上报频率要解耦</h2><p>采到新数据不代表必须立即发无线消息。常见策略是：</p><ul><li>本地按业务需要采样；</li><li>只有变化超过阈值时更新并上报；</li><li>设置最大报告间隔，保证长期稳定时仍有周期状态；</li><li>事件发生时可以复用最近的新鲜样本。</li></ul><p>无线发送的能量往往高于一次短 I2C 事务。只优化传感器模式，却让每次采样都触发无线报告，整体收益可能很有限。</p><h2 id="MCU-在转换期间是否真的睡着"><a href="#MCU-在转换期间是否真的睡着" class="headerlink" title="MCU 在转换期间是否真的睡着"></a>MCU 在转换期间是否真的睡着</h2><p>使用异步定时器只能说明系统具备休眠机会，并不保证每次等待都会进入低功耗状态。还要检查：</p><ul><li>协议栈是否繁忙；</li><li>是否有尚未完成的任务或日志输出；</li><li>最近的软件定时器是否允许进入目标睡眠模式；</li><li>I2C、GPIO 和传感器状态是否满足休眠门控；</li><li>唤醒后是否继续原状态机，而不是重复初始化采样。</li></ul><p>因此验证时不仅要看传感器寄存器，还要同时观察 MCU 的睡眠进入率和整机电流波形。</p><h2 id="是否值得电源门控"><a href="#是否值得电源门控" class="headerlink" title="是否值得电源门控"></a>是否值得电源门控</h2><p>如果传感器 Standby 仍占据不可接受的电流，可以考虑用 load switch 或受控电源完全断电。但这通常不是第一优先级，因为它会引入：</p><ul><li>每次采样重新上电和初始化；</li><li>I2C SDA&#x2F;SCL 通过上拉反向供电的风险；</li><li>GPIO 上电时序和高阻态要求；</li><li>额外器件、板级面积和故障路径；</li><li>校准或寄存器配置丢失。</li></ul><p>只有当整机预算确实需要节省最后几微安，并完成板级验证后，电源门控才可能值得。</p><h2 id="建议的验证矩阵"><a href="#建议的验证矩阵" class="headerlink" title="建议的验证矩阵"></a>建议的验证矩阵</h2><p>至少比较三种 profile：</p><table><thead><tr><th>Profile</th><th>配置</th><th>重点观察</th></tr></thead><tbody><tr><td>固定周期</td><td>每 5 秒按需 Active 一次</td><td>基准平均电流、数据新鲜度</td></tr><tr><td>事件优先</td><td>事件触发，加 30–60 秒 fallback</td><td>日常平均电流、事件响应</td></tr><tr><td>连续 IRQ</td><td>最长可接受 Measurement Rate，加阈值迟滞</td><td>阈值延迟、连续工作电流</td></tr></tbody></table><p>同时测量传感器电源轨和整机输入电流，覆盖：</p><ul><li>环境长期稳定；</li><li>事件频繁发生；</li><li>光照在阈值附近波动；</li><li>明暗快速切换；</li><li>I2C 失败和数据未就绪重试。</li></ul><p>静止十分钟的平均值只能代表一种场景。低功耗设计最终要在功耗、数据新鲜度、事件延迟和可靠恢复之间取得平衡。</p><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>环境光采集没有统一的“IRQ 一定更省电”答案。合理的选择顺序是：</p><ol><li>先确认传感器是否支持 single-shot 或低功耗阈值引擎；</li><li>再明确业务需要周期 lux，还是实时明暗事件；</li><li>不支持 single-shot 时，用状态机实现按需 Active 和可靠回 Standby；</li><li>优先合并请求、降低采样频率并对齐已有唤醒；</li><li>最后通过整机电流波形验证，而不是只依赖手册典型值。</li></ol><p>对于只需偶尔获取照度的电池设备，MCU 定时按需采样通常比连续 Active 加阈值 IRQ 更合适；而真正需要快速明暗检测时，连续 IRQ 的功耗代价应作为产品需求的一部分明确接受。</p>]]>
    </content>
    <id>https://onium.top/posts/ambient-light-sensor-low-power-sampling/</id>
    <link href="https://onium.top/posts/ambient-light-sensor-low-power-sampling/"/>
    <published>2026-07-29T07:30:00.000Z</published>
    <summary>
      <![CDATA[<p>在电池供电设备里，环境光传感器通常只需要偶尔提供一个 lux 值。此时“传感器带 IRQ”并不代表 IRQ 一定比定时读取省电。真正决定功耗的是：等待 IRQ 时传感器处于什么模式、转换期间 MCU 能否休眠，以及业务究竟需要周期数据还是实时阈值事件。</p>]]>
    </summary>
    <title>电池设备的环境光传感器：IRQ、单次采样与低功耗取舍</title>
    <updated>2026-07-29T07:49:30.676Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="生态适配" scheme="https://onium.top/categories/%E7%94%9F%E6%80%81%E9%80%82%E9%85%8D/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="SmartThings" scheme="https://onium.top/tags/smartthings/"/>
    <category term="ZHA" scheme="https://onium.top/tags/zha/"/>
    <category term="Zigbee2MQTT" scheme="https://onium.top/tags/zigbee2mqtt/"/>
    <content>
      <![CDATA[<p>同一台 Zigbee 设备在 ZHA、Zigbee2MQTT 和 SmartThings 中可能需要三套适配代码，但协议事实应该只有一份。高质量兼容工作的关键，是先建立产品中立的 Zigbee 行为矩阵，再把它映射到各平台的数据模型。</p><span id="more"></span><h2 id="三个平台分别在做什么"><a href="#三个平台分别在做什么" class="headerlink" title="三个平台分别在做什么"></a>三个平台分别在做什么</h2><table><thead><tr><th>平台</th><th>适配载体</th><th>主要语言</th><th>平台输出</th></tr></thead><tbody><tr><td>ZHA</td><td>Device Handler &#x2F; Quirk</td><td>Python</td><td>Home Assistant Entity、Device Automation</td></tr><tr><td>Zigbee2MQTT</td><td>zigbee-herdsman converter</td><td>JavaScript &#x2F; TypeScript</td><td>MQTT State、Command、Exposes</td></tr><tr><td>SmartThings</td><td>Edge Driver</td><td>Lua</td><td>SmartThings Capability 与 Component</td></tr></tbody></table><p>它们都要解决三件事：</p><ol><li>识别是哪一类设备；</li><li>把 Zigbee 消息转换成平台状态；</li><li>把平台操作转换成 Zigbee 命令或属性写入。</li></ol><h2 id="先判断是否真的需要第三方脚本"><a href="#先判断是否真的需要第三方脚本" class="headerlink" title="先判断是否真的需要第三方脚本"></a>先判断是否真的需要第三方脚本</h2><p>如果设备正确实现标准 Device Type、Cluster、Attribute、Command 和 Reporting，平台的通用处理通常已经能够覆盖主要功能。</p><p>适配脚本更适合处理：</p><ul><li>Basic Cluster 身份或描述符与实际行为不一致；</li><li>厂商自定义 Cluster、Attribute 或 Command；</li><li>标准位图需要拆成多个平台实体；</li><li>原始数值需要单位、比例或枚举转换；</li><li>特定固件版本存在兼容差异；</li><li>标准功能存在，但平台没有自动生成期望的实体或 Capability。</li></ul><p>能在固件端修复的标准合规问题，不应长期依赖三个平台分别打补丁。</p><h2 id="建立一份协议事实矩阵"><a href="#建立一份协议事实矩阵" class="headerlink" title="建立一份协议事实矩阵"></a>建立一份协议事实矩阵</h2><p>每项能力至少记录：</p><table><thead><tr><th>字段</th><th>内容</th></tr></thead><tbody><tr><td>身份</td><td>Manufacturer、Model、固件版本</td></tr><tr><td>拓扑</td><td>Endpoint、Profile ID、Device ID</td></tr><tr><td>Cluster</td><td>Server &#x2F; Client 方向</td></tr><tr><td>数据源</td><td>Attribute、Command 或 ZDO 消息</td></tr><tr><td>原始类型</td><td>bitmap、enum、signed、unsigned、string</td></tr><tr><td>转换</td><td>单位、倍率、范围、无效值</td></tr><tr><td>上行</td><td>Report、Read Response、Cluster Command</td></tr><tr><td>下行</td><td>Write、Command、Configure Reporting</td></tr><tr><td>生命周期</td><td>首次加入、重启、rejoin、恢复出厂</td></tr><tr><td>低功耗</td><td>Poll、唤醒窗口和配置时机</td></tr></tbody></table><p>平台代码只消费这份事实，不重新猜测协议含义。</p><h2 id="平台映射表"><a href="#平台映射表" class="headerlink" title="平台映射表"></a>平台映射表</h2><table><thead><tr><th>Zigbee 事实</th><th>ZHA</th><th>Zigbee2MQTT</th><th>SmartThings</th></tr></thead><tbody><tr><td>Manufacturer &#x2F; Model</td><td>QuirkBuilder matcher</td><td><code>zigbeeModel</code> &#x2F; fingerprint</td><td><code>fingerprints.yml</code></td></tr><tr><td>Attribute Report</td><td>Cluster update &#x2F; Entity</td><td><code>fromZigbee</code> &#x2F; modern extend</td><td><code>zigbee_handlers.attr</code></td></tr><tr><td>Cluster Command</td><td>automation trigger</td><td><code>fromZigbee</code> action</td><td><code>zigbee_handlers.cluster</code></td></tr><tr><td>平台控制</td><td>Entity write&#x2F;command</td><td><code>toZigbee</code></td><td>Capability handler</td></tr><tr><td>对外能力</td><td>Entity metadata</td><td><code>exposes</code></td><td>Profile Capability</td></tr><tr><td>Reporting</td><td>ReportingConfig</td><td><code>configure</code> &#x2F; modern extend</td><td>configured&#x2F;monitored attribute</td></tr><tr><td>设备变体</td><td>firmware filter &#x2F; matcher</td><td>fingerprint &#x2F; meta</td><td>sub-driver <code>can_handle</code></td></tr></tbody></table><p>名字相近不表示行为自动相同。例如同一个 IAS Zone 位图，在一个平台可能拆成多个 Binary Sensor，在另一个平台可能形成一组 MQTT 属性，在 SmartThings 中则对应多个 Capability。</p><h2 id="推荐开发顺序"><a href="#推荐开发顺序" class="headerlink" title="推荐开发顺序"></a>推荐开发顺序</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">抓取真实 interview 与空口行为</span><br><span class="line">  -&gt; 建立协议事实矩阵</span><br><span class="line">  -&gt; 先验证标准能力</span><br><span class="line">  -&gt; 实现最小身份匹配</span><br><span class="line">  -&gt; 实现上行状态</span><br><span class="line">  -&gt; 实现下行控制</span><br><span class="line">  -&gt; 配置 reporting / binding</span><br><span class="line">  -&gt; 验证重启、rejoin 与低功耗</span><br><span class="line">  -&gt; 三平台对照回归</span><br></pre></td></tr></table></figure><p>不要一开始就复制相似设备脚本。先比较 Endpoint、Cluster 方向、属性类型和命令载荷，确认差异后再复用。</p><h2 id="身份匹配要足够窄"><a href="#身份匹配要足够窄" class="headerlink" title="身份匹配要足够窄"></a>身份匹配要足够窄</h2><p>过宽匹配会让行为不同的设备误用同一脚本：</p><ul><li>只按常见 Model ID 匹配，可能碰到多个厂商共用；</li><li>只按 Cluster 集合匹配，可能覆盖大量标准设备；</li><li>忽略固件版本，可能把旧固件 workaround 应用于新固件；</li><li>忽略 Endpoint，可能把多路设备映射到错误 Component。</li></ul><p>优先使用稳定的 Manufacturer + Model；必要时叠加 Endpoint、Cluster 或固件版本条件。更换身份字符串会破坏已经发布的三平台兼容代码，应视为协议接口变更。</p><h2 id="上行与下行必须成对验证"><a href="#上行与下行必须成对验证" class="headerlink" title="上行与下行必须成对验证"></a>上行与下行必须成对验证</h2><p>一个“可见的开关”不代表完整兼容：</p><ul><li>设备主动变化能否更新平台；</li><li>平台写入能否改变设备；</li><li>Read Back 是否与平台状态一致；</li><li>失败是否返回真实错误；</li><li>重启后状态能否恢复；</li><li>reporting 丢失后能否重新配置；</li><li>Sleepy End Device 是否在唤醒窗口处理配置。</li></ul><p>如果只验证 UI 点击成功，很容易漏掉设备侧主动变化和离线恢复。</p><h2 id="三个平台的状态命名"><a href="#三个平台的状态命名" class="headerlink" title="三个平台的状态命名"></a>三个平台的状态命名</h2><p>建议先定义平台无关语义：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">contact: open / closed</span><br><span class="line">tamper: detected / clear</span><br><span class="line">battery: percentage</span><br><span class="line">alarm: active / inactive</span><br></pre></td></tr></table></figure><p>然后分别映射为：</p><ul><li>ZHA 的 Entity 和 Device Class；</li><li>Z2M 的 <code>exposes</code> property；</li><li>SmartThings 的 Capability attribute&#x2F;event。</li></ul><p>协议枚举值保持不变，显示文案可以平台化。不要为了让 UI 好看而改变空口数值。</p><h2 id="低功耗设备专项"><a href="#低功耗设备专项" class="headerlink" title="低功耗设备专项"></a>低功耗设备专项</h2><p>兼容脚本常在设备刚加入时集中执行 bind、read 和 configure reporting。对休眠设备，应检查：</p><ul><li>配置发生时设备是否仍处于 Fast Poll；</li><li>平台是否会自动重试；</li><li>rejoin 后 reporting 是否保留；</li><li>父节点更换后是否需要重新绑定；</li><li>多条配置是否超出单次唤醒窗口；</li><li>失败是否被静默忽略。</li></ul><p>“第一次加入能用”不足以证明长期兼容。</p><h2 id="验证证据分层"><a href="#验证证据分层" class="headerlink" title="验证证据分层"></a>验证证据分层</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">脚本能加载</span><br><span class="line">  != 匹配到目标设备</span><br><span class="line">  != Entity / Exposes / Capability 正确</span><br><span class="line">  != 上行状态正确</span><br><span class="line">  != 下行控制正确</span><br><span class="line">  != 重启和 rejoin 正确</span><br><span class="line">  != 平台正式收录</span><br><span class="line">  != Zigbee 认证或生态认证</span><br></pre></td></tr></table></figure><p>每个平台都应保存版本、脚本提交、interview、调试日志、测试动作和预期结果。公开问题单要脱敏设备唯一地址、Network Key、install code 和私有仓库信息。</p><p>继续阅读：</p><ul><li><a href="https://github.com/zigpy/zha-device-handlers">ZHA Device Handlers</a></li><li><a href="https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html">Zigbee2MQTT 新设备支持</a></li><li><a href="https://developer.smartthings.com/docs/devices/hub-connected/edge-architecture">SmartThings Edge 架构</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/zigbee-third-party-platform-compatibility/</id>
    <link href="https://onium.top/posts/zigbee-third-party-platform-compatibility/"/>
    <published>2026-07-29T02:40:00.000Z</published>
    <summary>
      <![CDATA[<p>同一台 Zigbee 设备在 ZHA、Zigbee2MQTT 和 SmartThings 中可能需要三套适配代码，但协议事实应该只有一份。高质量兼容工作的关键，是先建立产品中立的 Zigbee 行为矩阵，再把它映射到各平台的数据模型。</p>]]>
    </summary>
    <title>Zigbee 第三方平台适配：ZHA、Z2M 与 SmartThings 的统一方法</title>
    <updated>2026-07-29T02:49:46.132Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="生态适配" scheme="https://onium.top/categories/%E7%94%9F%E6%80%81%E9%80%82%E9%85%8D/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="ZHA" scheme="https://onium.top/tags/zha/"/>
    <category term="Home Assistant" scheme="https://onium.top/tags/home-assistant/"/>
    <category term="Python" scheme="https://onium.top/tags/python/"/>
    <content>
      <![CDATA[<p>ZHA Quirk 是 Zigpy 与 Home Assistant 之间的设备适配层。它适合修正非标准描述符、补充厂商 Cluster，或把已有 Zigbee 属性映射成正确的 Home Assistant Entity。</p><span id="more"></span><h2 id="Quirk-的边界"><a href="#Quirk-的边界" class="headerlink" title="Quirk 的边界"></a>Quirk 的边界</h2><p>一个 Quirk 通常包含：</p><ul><li>Matcher：识别 Manufacturer、Model 和可选的设备条件；</li><li>Cluster modification：增加、移除或替换 Cluster；</li><li>Entity metadata：把属性或命令映射成 Entity；</li><li>Automation trigger：把遥控器命令映射成设备动作；</li><li>Reporting configuration：声明需要配置的属性上报。</li></ul><p>Quirk 不会修复射频、入网安全或设备没有发送报文的问题。先确认目标报文确实到达 Zigpy，再处理映射。</p><h2 id="优先使用-V2-QuirkBuilder"><a href="#优先使用-V2-QuirkBuilder" class="headerlink" title="优先使用 V2 QuirkBuilder"></a>优先使用 V2 QuirkBuilder</h2><p>当前 zha-device-handlers 推荐新适配使用声明式 <code>QuirkBuilder</code>。一个只补充 IAS Zone Tamper 实体的通用示例：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> zigpy.zcl.clusters.security <span class="keyword">import</span> IasZone</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> zhaquirks.builder <span class="keyword">import</span> BinarySensorDeviceClass, QuirkBuilder</span><br><span class="line"></span><br><span class="line">(</span><br><span class="line">    QuirkBuilder(<span class="string">&quot;Example Manufacturer&quot;</span>, <span class="string">&quot;GENERIC-CONTACT-01&quot;</span>)</span><br><span class="line">    .binary_sensor(</span><br><span class="line">        attribute_name=IasZone.AttributeDefs.zone_status.name,</span><br><span class="line">        cluster_id=IasZone.cluster_id,</span><br><span class="line">        device_class=BinarySensorDeviceClass.TAMPER,</span><br><span class="line">        attribute_converter=<span class="keyword">lambda</span> value: <span class="built_in">bool</span>(</span><br><span class="line">            value &amp; IasZone.ZoneStatus.Tamper</span><br><span class="line">        ),</span><br><span class="line">        unique_id_suffix=<span class="string">&quot;tamper&quot;</span>,</span><br><span class="line">        fallback_name=<span class="string">&quot;Tamper&quot;</span>,</span><br><span class="line">    )</span><br><span class="line">    .add_to_registry()</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>这个示例假设设备已经正确提供 IAS Zone Cluster，只是平台需要把 <code>zone_status</code> 的 Tamper 位拆成独立实体。它没有虚构 Cluster，也没有改变空口数据。</p><h2 id="Matcher-为什么经常失败"><a href="#Matcher-为什么经常失败" class="headerlink" title="Matcher 为什么经常失败"></a>Matcher 为什么经常失败</h2><p>先从 ZHA Device Signature 或调试日志确认：</p><ul><li>Basic Cluster 的 Manufacturer；</li><li>Model；</li><li>Endpoint 列表；</li><li>每个 Endpoint 的 Profile、Device Type；</li><li>Server &#x2F; Client Cluster。</li></ul><p>字符串必须与设备实际返回完全一致。营销名称、包装型号和 Basic Cluster Model 可能不同。</p><p>如果多个固件共享 Manufacturer&#x2F;Model 但行为不同，可使用固件版本过滤或更具体条件，避免一个 workaround 覆盖所有版本。</p><h2 id="什么时候替换-Cluster"><a href="#什么时候替换-Cluster" class="headerlink" title="什么时候替换 Cluster"></a>什么时候替换 Cluster</h2><p>只有出现以下情况才需要自定义 Cluster：</p><ul><li>厂商 Cluster 未在 Zigpy 中定义；</li><li>属性类型、Manufacturer Code 或访问方式需要补充；</li><li>报告值需要稳定、可证明的转换；</li><li>标准 Cluster 的设备实现存在已确认偏差。</li></ul><p>自定义属性应明确：</p><ul><li>Attribute ID；</li><li>Zigbee 数据类型；</li><li>读写权限；</li><li>Manufacturer Code；</li><li>单位与缩放；</li><li>无效值；</li><li>reporting 行为。</li></ul><p>不要根据一条抓包就猜测类型。至少验证边界值、重启和多个样机。</p><h2 id="Server-与-Client-方向"><a href="#Server-与-Client-方向" class="headerlink" title="Server 与 Client 方向"></a>Server 与 Client 方向</h2><p>ZHA 中：</p><ul><li><code>in_clusters</code> 对应设备提供的 Server Cluster；</li><li><code>out_clusters</code> 对应设备使用的 Client Cluster。</li></ul><p>命令定义的方向也要与 Zigpy 当前 API 一致。升级 Zigpy 时，如果命令定义模型发生变化，应保持 Command ID、载荷类型和空口序列化不变。</p><h2 id="Entity-映射注意点"><a href="#Entity-映射注意点" class="headerlink" title="Entity 映射注意点"></a>Entity 映射注意点</h2><p>建立 Entity 时核对：</p><ul><li><code>endpoint_id</code>；</li><li><code>cluster_id</code>；</li><li><code>attribute_name</code> 或 <code>command_name</code>；</li><li>Device Class；</li><li>Entity Type：Standard、Config 或 Diagnostic；</li><li>单位、倍率和显示精度；</li><li><code>unique_id_suffix</code> 是否稳定且无冲突；</li><li>是否默认禁用。</li></ul><p>同一个位图拆成多个实体时，每个实体都要使用稳定且不同的 suffix。已有用户依赖 Entity ID 后，不应随意更换。</p><h2 id="本地加载"><a href="#本地加载" class="headerlink" title="本地加载"></a>本地加载</h2><p>Home Assistant 可通过 ZHA 配置加载自定义 quirks：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">zha:</span></span><br><span class="line">  <span class="attr">custom_quirks_path:</span> <span class="string">/config/custom_zha_quirks</span></span><br></pre></td></tr></table></figure><p>把 Python 文件放入该目录后重启 Home Assistant。随后在设备信息与日志中确认实际加载的 Quirk 类。</p><p>如果 Quirk 已匹配但新实体仍未出现，可先执行重新配置；只有在确认平台没有重建设备实体时，再评估删除并重新配对。重新配对不是验证 Matcher 的替代方法。</p><h2 id="最小验证"><a href="#最小验证" class="headerlink" title="最小验证"></a>最小验证</h2><p>开发仓库中的常见检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">python -m py_compile path/to/quirk.py</span><br><span class="line">ruff check path/to/quirk.py</span><br><span class="line">pytest path/to/relevant_tests.py</span><br></pre></td></tr></table></figure><p>还需要设备侧验证：</p><ol><li>Quirk 被目标设备匹配；</li><li>相似设备不被误匹配；</li><li>属性报告更新正确实体；</li><li>写入或命令使用正确 Endpoint 和方向；</li><li>重启 Home Assistant 后仍可加载；</li><li>设备 rejoin 后 reporting 正常；</li><li>未知值不会导致异常或错误状态。</li></ol><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><table><thead><tr><th>症状</th><th>先检查</th></tr></thead><tbody><tr><td>Quirk 没加载</td><td>Manufacturer、Model、签名与加载路径</td></tr><tr><td>Quirk 加载但无实体</td><td>Entity metadata、Cluster 方向、Entity registry</td></tr><tr><td>实体不更新</td><td>Attribute ID、报告方向、converter</td></tr><tr><td>写入失败</td><td>权限、Manufacturer Code、Endpoint、设备唤醒</td></tr><tr><td>多个 Quirk 冲突</td><td>Matcher 是否过宽、版本是否重复注册</td></tr><tr><td>升级后警告</td><td>Zigpy&#x2F;ZHA API 与命令定义版本</td></tr></tbody></table><p>正式贡献前应遵守仓库当前的格式、类型检查、测试和贡献说明。官方入口：</p><ul><li><a href="https://github.com/zigpy/zha-device-handlers">zha-device-handlers</a></li><li><a href="https://www.home-assistant.io/integrations/zha/">Home Assistant ZHA 集成</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/zha-custom-quirk-development/</id>
    <link href="https://onium.top/posts/zha-custom-quirk-development/"/>
    <published>2026-07-29T02:30:00.000Z</published>
    <summary>
      <![CDATA[<p>ZHA Quirk 是 Zigpy 与 Home Assistant 之间的设备适配层。它适合修正非标准描述符、补充厂商 Cluster，或把已有 Zigbee 属性映射成正确的 Home Assistant Entity。</p>]]>
    </summary>
    <title>ZHA 第三方设备兼容：用 V2 Quirk 精确匹配和映射实体</title>
    <updated>2026-07-29T02:49:46.133Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="生态适配" scheme="https://onium.top/categories/%E7%94%9F%E6%80%81%E9%80%82%E9%85%8D/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="Zigbee2MQTT" scheme="https://onium.top/tags/zigbee2mqtt/"/>
    <category term="JavaScript" scheme="https://onium.top/tags/javascript/"/>
    <category term="MQTT" scheme="https://onium.top/tags/mqtt/"/>
    <content>
      <![CDATA[<p>Zigbee2MQTT 使用 zigbee-herdsman-converters 把 Zigbee 消息转换成 MQTT 状态和命令。External Converter 可以在不修改正式安装包的情况下开发和验证新设备支持。</p><span id="more"></span><h2 id="开始前先做三件事"><a href="#开始前先做三件事" class="headerlink" title="开始前先做三件事"></a>开始前先做三件事</h2><ol><li>检查设备是否已在 Zigbee2MQTT 开发分支获得支持；</li><li>把日志级别设为 Debug；</li><li>完成设备 interview，并保存 Endpoint、Cluster 与 Basic 信息。</li></ol><p>能加入网络只代表 Zigbee2MQTT 可以访问设备，不代表已有 converter 能理解它。</p><h2 id="先生成外部定义"><a href="#先生成外部定义" class="headerlink" title="先生成外部定义"></a>先生成外部定义</h2><p>当前 Zigbee2MQTT 前端可以在设备的 Dev console 中生成 external definition。生成结果基于发现到的标准 Cluster，应先验证 Exposes 页面中的能力是否真实可用。</p><p>自动生成的定义是起点，不是最终结论：</p><ul><li>设备可能没有上报全部能力；</li><li>厂商 Cluster 无法自动理解；</li><li>reporting 可能尚未配置；</li><li>命令型遥控器可能没有普通状态属性；</li><li>相同 Model ID 可能对应多个厂商变体。</li></ul><h2 id="Modern-Extend-示例"><a href="#Modern-Extend-示例" class="headerlink" title="Modern Extend 示例"></a>Modern Extend 示例</h2><p>标准温湿度与电池设备可以从最小定义开始：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;</span><br><span class="line">    battery,</span><br><span class="line">    humidity,</span><br><span class="line">    temperature,</span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">&quot;zigbee-herdsman-converters/lib/modernExtend&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="attr">zigbeeModel</span>: [<span class="string">&quot;GENERIC-ENV-01&quot;</span>],</span><br><span class="line">    <span class="attr">model</span>: <span class="string">&quot;GENERIC-ENV-01&quot;</span>,</span><br><span class="line">    <span class="attr">vendor</span>: <span class="string">&quot;Example Vendor&quot;</span>,</span><br><span class="line">    <span class="attr">description</span>: <span class="string">&quot;Temperature and humidity sensor&quot;</span>,</span><br><span class="line">    <span class="attr">extend</span>: [</span><br><span class="line">        <span class="title function_">temperature</span>(),</span><br><span class="line">        <span class="title function_">humidity</span>(),</span><br><span class="line">        <span class="title function_">battery</span>(),</span><br><span class="line">    ],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Modern extends 会组合常见的 <code>fromZigbee</code>、<code>toZigbee</code>、<code>exposes</code> 和配置逻辑。能复用时优先复用，减少重复的解析和 reporting 代码。</p><h2 id="External-Converter-放在哪里"><a href="#External-Converter-放在哪里" class="headerlink" title="External Converter 放在哪里"></a>External Converter 放在哪里</h2><p>文件通常放在与 Zigbee2MQTT <code>configuration.yaml</code> 同级的 <code>external_converters</code> 目录，例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">data/</span><br><span class="line">├── configuration.yaml</span><br><span class="line">└── external_converters/</span><br><span class="line">    └── generic-env.mjs</span><br></pre></td></tr></table></figure><p>也可以从前端的 Settings → Dev console → External converters 加载和更新。</p><p>当前版本对外部 JavaScript 有额外安全控制。它会在 Zigbee2MQTT 进程中执行任意代码，只应在隔离的开发环境中启用，并只加载经过审查的来源。</p><h2 id="什么时候使用-fromZigbee"><a href="#什么时候使用-fromZigbee" class="headerlink" title="什么时候使用 fromZigbee"></a>什么时候使用 fromZigbee</h2><p><code>fromZigbee</code> 负责把设备发来的消息转换成平台状态或 action：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Attribute Report / Read Response / Cluster Command</span><br><span class="line">  -&gt; 匹配 cluster 与 message type</span><br><span class="line">  -&gt; 解析原始字段</span><br><span class="line">  -&gt; 校验范围和特殊值</span><br><span class="line">  -&gt; 返回 MQTT property</span><br></pre></td></tr></table></figure><p>如果日志持续出现 <code>No converter available</code>，先确认：</p><ul><li>Cluster 名称；</li><li>Message type；</li><li>Endpoint；</li><li>Attribute 或 Command ID；</li><li>是否已存在可复用 converter；</li><li>是否已经被某个 modern extend 覆盖。</li></ul><p>不要用一个接受所有消息的 converter 隐藏未知数据。</p><h2 id="什么时候使用-toZigbee"><a href="#什么时候使用-toZigbee" class="headerlink" title="什么时候使用 toZigbee"></a>什么时候使用 toZigbee</h2><p><code>toZigbee</code> 把 MQTT Set&#x2F;Get 转换成 Attribute Read&#x2F;Write 或 Cluster Command。必须定义：</p><ul><li>支持的 property；</li><li>输入类型和范围；</li><li>枚举字符串与协议数值；</li><li>目标 Endpoint；</li><li>Manufacturer Code；</li><li>写入后的状态确认策略；</li><li>错误返回。</li></ul><p>下发函数返回成功不等于设备状态已经改变。应结合响应、Read Back 或后续 Report。</p><h2 id="Exposes-是公开契约"><a href="#Exposes-是公开契约" class="headerlink" title="Exposes 是公开契约"></a>Exposes 是公开契约</h2><p><code>exposes</code> 决定前端和 MQTT 使用者看到什么。每个 property 应明确：</p><ul><li>名称与显示 Label；</li><li>读、写、状态访问；</li><li>数据类型；</li><li>单位；</li><li>最小值、最大值和步进；</li><li>枚举；</li><li>Endpoint 后缀；</li><li>描述。</li></ul><p>一旦用户用 property 编写自动化，随意改名会造成兼容破坏。显示文案可以优化，但 MQTT property 应保持稳定。</p><h2 id="Configure-与-reporting"><a href="#Configure-与-reporting" class="headerlink" title="Configure 与 reporting"></a>Configure 与 reporting</h2><p>设备没有主动上报时，可能需要在 <code>configure</code> 中：</p><ul><li>bind 到 Coordinator Endpoint；</li><li>Configure Reporting；</li><li>读取倍率、除数或初始状态；</li><li>设置厂商初始化属性。</li></ul><p>对 Sleepy End Device，配置必须落在唤醒窗口，并验证失败重试。不要假设一次 <code>configure</code> 成功就会永久保留；还要测试断电、rejoin 和恢复出厂。</p><h2 id="匹配多个设备变体"><a href="#匹配多个设备变体" class="headerlink" title="匹配多个设备变体"></a>匹配多个设备变体</h2><p><code>zigbeeModel</code> 简单但可能过宽。多个厂商共用同一 Model ID 时，应使用更精确的 fingerprint 条件，并把真正相同的行为复用到公共 extend。</p><p>兼容层次建议：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">标准 modern extend</span><br><span class="line">  -&gt; 品类公共 converter</span><br><span class="line">  -&gt; 厂商公共逻辑</span><br><span class="line">  -&gt; 设备或固件差异</span><br></pre></td></tr></table></figure><p>不要把所有变体堆进一个充满 Model 判断的转换函数。</p><h2 id="验证清单"><a href="#验证清单" class="headerlink" title="验证清单"></a>验证清单</h2><ol><li>Converter 成功加载；</li><li>只匹配预期设备；</li><li>Exposes 完整且访问方向正确；</li><li>所有上行属性和命令均可解析；</li><li>Set&#x2F;Get 有真实设备结果；</li><li>reporting、单位和缩放正确；</li><li>多 Endpoint property 不冲突；</li><li>Zigbee2MQTT 重启后仍可加载；</li><li>设备断电和 rejoin 后恢复；</li><li>Debug 日志没有未解释的消息和异常。</li></ol><p>External Converter 验证完成后，可按 zigbee-herdsman-converters 当前结构转成正式 TypeScript definition 并提交上游。发布版本已经包含支持后，应移除本地 converter，避免重复匹配。</p><p>官方资料：</p><ul><li><a href="https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html">支持新设备</a></li><li><a href="https://www.zigbee2mqtt.io/advanced/more/external_converters.html">External Converters</a></li><li><a href="https://www.zigbee2mqtt.io/guide/usage/exposes.html">Exposes</a></li><li><a href="https://www.zigbee2mqtt.io/advanced/zigbee/03_secure_network.html">外部脚本安全说明</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/zigbee2mqtt-external-converter-development/</id>
    <link href="https://onium.top/posts/zigbee2mqtt-external-converter-development/"/>
    <published>2026-07-29T02:20:00.000Z</published>
    <summary>
      <![CDATA[<p>Zigbee2MQTT 使用 zigbee-herdsman-converters 把 Zigbee 消息转换成 MQTT 状态和命令。External Converter 可以在不修改正式安装包的情况下开发和验证新设备支持。</p>]]>
    </summary>
    <title>Zigbee2MQTT 第三方设备兼容：External Converter 开发与验证</title>
    <updated>2026-07-29T02:49:46.134Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="生态适配" scheme="https://onium.top/categories/%E7%94%9F%E6%80%81%E9%80%82%E9%85%8D/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="SmartThings" scheme="https://onium.top/tags/smartthings/"/>
    <category term="Edge Driver" scheme="https://onium.top/tags/edge-driver/"/>
    <category term="Lua" scheme="https://onium.top/tags/lua/"/>
    <content>
      <![CDATA[<p>SmartThings Edge Driver 在 Hub 本地运行，用 Lua 把 Zigbee 设备行为转换成 SmartThings Capability。兼容工作的核心不是写很多 Handler，而是让 fingerprint、profile、默认处理和设备差异保持一致。</p><span id="more"></span><h2 id="Driver-目录结构"><a href="#Driver-目录结构" class="headerlink" title="Driver 目录结构"></a>Driver 目录结构</h2><p>一个 Zigbee Edge Driver 通常包含：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">zigbee-example/</span><br><span class="line">├── config.yml</span><br><span class="line">├── fingerprints.yml</span><br><span class="line">├── profiles/</span><br><span class="line">│   └── sensor.yml</span><br><span class="line">└── src/</span><br><span class="line">    ├── init.lua</span><br><span class="line">    └── sub_drivers/</span><br><span class="line">        └── device_variant/</span><br><span class="line">            ├── can_handle.lua</span><br><span class="line">            └── init.lua</span><br></pre></td></tr></table></figure><ul><li><code>config.yml</code>：包信息、权限和 Edge API 版本；</li><li><code>fingerprints.yml</code>：设备匹配与 Profile 选择；</li><li><code>profiles/</code>：Component 和 Capability；</li><li><code>src/</code>：Zigbee Handler、Capability Handler 与生命周期逻辑；</li><li><code>sub_drivers/</code>：只覆盖特定设备差异。</li></ul><h2 id="Fingerprint"><a href="#Fingerprint" class="headerlink" title="Fingerprint"></a>Fingerprint</h2><p>Manufacturer-specific fingerprint 适合已知设备：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">zigbeeManufacturer:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">&quot;example/generic-contact-v1&quot;</span></span><br><span class="line">    <span class="attr">manufacturer:</span> <span class="string">&quot;Example Manufacturer&quot;</span></span><br><span class="line">    <span class="attr">model:</span> <span class="string">&quot;GENERIC-CONTACT-01&quot;</span></span><br><span class="line">    <span class="attr">deviceProfileName:</span> <span class="string">&quot;contact-battery&quot;</span></span><br><span class="line">    <span class="attr">deviceLabel:</span> <span class="string">&quot;Generic contact sensor&quot;</span></span><br></pre></td></tr></table></figure><p>字段必须来自设备实际报告，而不是包装名称。</p><p>SmartThings 也支持按 Profile、Device ID 和 Server&#x2F;Client Cluster 匹配的 generic fingerprint。它适合真正遵循标准且行为一致的设备；设备存在特殊处理时，精确 Manufacturer&#x2F;Model 匹配更安全。</p><h2 id="Profile-是平台契约"><a href="#Profile-是平台契约" class="headerlink" title="Profile 是平台契约"></a>Profile 是平台契约</h2><p>Profile 决定 App 和自动化看到的 Capability：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">contact-battery</span></span><br><span class="line"><span class="attr">components:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">main</span></span><br><span class="line">    <span class="attr">capabilities:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">contactSensor</span></span><br><span class="line">        <span class="attr">version:</span> <span class="number">1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">battery</span></span><br><span class="line">        <span class="attr">version:</span> <span class="number">1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">tamperAlert</span></span><br><span class="line">        <span class="attr">version:</span> <span class="number">1</span></span><br><span class="line">    <span class="attr">categories:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">ContactSensor</span></span><br></pre></td></tr></table></figure><p>只有 Driver 能稳定产生和处理的 Capability 才应加入 Profile。删除或重命名已部署 Profile 会影响现有设备，应作为兼容性变更评估。</p><h2 id="先使用默认-Zigbee-Handler"><a href="#先使用默认-Zigbee-Handler" class="headerlink" title="先使用默认 Zigbee Handler"></a>先使用默认 Zigbee Handler</h2><p>SmartThings Zigbee library 已提供常见 ZCL 到 Capability 的默认映射：</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> capabilities = <span class="built_in">require</span> <span class="string">&quot;st.capabilities&quot;</span></span><br><span class="line"><span class="keyword">local</span> defaults = <span class="built_in">require</span> <span class="string">&quot;st.zigbee.defaults&quot;</span></span><br><span class="line"></span><br><span class="line">defaults.register_for_default_handlers(</span><br><span class="line">  driver_template,</span><br><span class="line">  &#123;</span><br><span class="line">    capabilities.contactSensor,</span><br><span class="line">    capabilities.battery,</span><br><span class="line">  &#125;</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>标准功能优先使用默认处理。自定义 <code>zigbee_handlers</code> 会覆盖相同 Cluster&#x2F;Attribute 的默认 Handler，因此只覆盖设备真正偏离标准的部分。</p><h2 id="自定义-Zigbee-Handler"><a href="#自定义-Zigbee-Handler" class="headerlink" title="自定义 Zigbee Handler"></a>自定义 Zigbee Handler</h2><p>Handler 按消息类型组织：</p><ul><li><code>attr</code>：Attribute Report 或 Read Response；</li><li><code>cluster</code>：Cluster-specific Command；</li><li><code>global</code>：ZCL Global Command；</li><li><code>zdo</code>：ZDO 消息。</li></ul><p>一个属性处理的结构：</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> clusters = <span class="built_in">require</span> <span class="string">&quot;st.zigbee.zcl.clusters&quot;</span></span><br><span class="line"><span class="keyword">local</span> OnOff = clusters.OnOff</span><br><span class="line"></span><br><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> <span class="title">on_off_handler</span><span class="params">(driver, device, value, zb_rx)</span></span></span><br><span class="line">  <span class="comment">-- 校验 value，再产生对应 Capability event</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">driver_template.zigbee_handlers = &#123;</span><br><span class="line">  attr = &#123;</span><br><span class="line">    [OnOff.ID] = &#123;</span><br><span class="line">      [OnOff.attributes.OnOff.ID] = on_off_handler,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>真实实现还应处理数据类型、Endpoint、多 Component 映射和未知值。</p><h2 id="Capability-Handler"><a href="#Capability-Handler" class="headerlink" title="Capability Handler"></a>Capability Handler</h2><p>App 发出的 Capability command 需要转换成 Zigbee Command 或 Attribute Write：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Capability command</span><br><span class="line">  -&gt; 校验参数</span><br><span class="line">  -&gt; 选择 Component / Endpoint</span><br><span class="line">  -&gt; 构造 ZCL message</span><br><span class="line">  -&gt; device:send(...)</span><br><span class="line">  -&gt; 等待设备响应或后续 report</span><br></pre></td></tr></table></figure><p>不要在发送后无条件伪造成功状态，除非平台交互明确要求 optimistic update，并且随后有校正机制。</p><h2 id="Reporting-与-doConfigure"><a href="#Reporting-与-doConfigure" class="headerlink" title="Reporting 与 doConfigure"></a>Reporting 与 doConfigure</h2><p>ZigbeeDevice 可以登记 configured 或 monitored attributes。设备配置时，库可执行 bind 和 Configure Reporting；特殊设备也可以在 <code>doConfigure</code> 中发送自定义配置。</p><p>核对：</p><ul><li>Cluster、Attribute 和数据类型；</li><li>Minimum &#x2F; Maximum Interval；</li><li>Reportable Change；</li><li>Hub Endpoint；</li><li>Sleepy End Device 的唤醒窗口；</li><li>配置失败后的重试；</li><li>rejoin 后是否需要重新配置。</li></ul><p>过度频繁的 reporting 会增加网络负载和电池消耗。</p><h2 id="Sub-driver-隔离设备差异"><a href="#Sub-driver-隔离设备差异" class="headerlink" title="Sub-driver 隔离设备差异"></a>Sub-driver 隔离设备差异</h2><p>同一品类 Driver 可以支持多种设备。标准行为放在主 Driver，只有特定设备的差异放入 sub-driver，并通过 <code>can_handle</code> 精确匹配。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">主 Driver：通用 Capability 与默认 Handler</span><br><span class="line">  -&gt; sub-driver A：特殊属性转换</span><br><span class="line">  -&gt; sub-driver B：不同 Endpoint 映射</span><br><span class="line">  -&gt; sub-driver C：旧固件 workaround</span><br></pre></td></tr></table></figure><p>避免在每个 Handler 中堆叠大量 Manufacturer&#x2F;Model 判断。</p><h2 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h2><p>常见生命周期包括：</p><ul><li><code>added</code>：设备首次创建；</li><li><code>init</code>：Driver 启动或设备初始化；</li><li><code>doConfigure</code>：配置 binding 和 reporting；</li><li><code>infoChanged</code>：Preferences 变化；</li><li><code>removed</code>：设备移除。</li></ul><p>不要把所有网络操作都放在 <code>init</code>，否则每次 Driver 重启可能重复配置大量设备。</p><h2 id="本地打包与设备验证"><a href="#本地打包与设备验证" class="headerlink" title="本地打包与设备验证"></a>本地打包与设备验证</h2><p>SmartThings CLI 可以只构建 zip、不上传：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:drivers:package \</span><br><span class="line">  --build-only driver.zip \</span><br><span class="line">  path/to/driver</span><br></pre></td></tr></table></figure><p>这个步骤验证包结构，但不证明 Hub 运行正确。上传、Channel 分配和 Hub 安装会改变云端或设备状态，应在明确的测试环境中单独执行。</p><p>Hub 验证时使用 live log：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">smartthings edge:drivers:logcat --hub-address=&lt;HUB_IP&gt;</span><br></pre></td></tr></table></figure><p>Hub 地址、Channel ID、Driver ID 和认证 Token 不应提交到公开仓库。</p><h2 id="测试矩阵"><a href="#测试矩阵" class="headerlink" title="测试矩阵"></a>测试矩阵</h2><p>至少覆盖：</p><ol><li>fingerprint 选中正确 Profile；</li><li>相似设备不会误匹配；</li><li>Attribute Report 产生正确 Capability event；</li><li>Cluster Command 产生正确 action；</li><li>Capability command 发送正确 ZCL 消息；</li><li>reporting 配置与低功耗行为；</li><li>多 Endpoint 到 Component 的映射；</li><li>Driver 重启、设备 rejoin 和恢复出厂；</li><li>Preferences 更新；</li><li>未知值和发送失败。</li></ol><p>涉及公开 SmartThingsEdgeDrivers 仓库与认证的变更，还应提供官方要求的集成测试。Package build、Hub 实测、公开仓库合入和 Works with SmartThings 认证是四个不同结果。</p><p>官方资料：</p><ul><li><a href="https://developer.smartthings.com/docs/devices/hub-connected/driver-components-and-structure">Driver 结构与 Fingerprint</a></li><li><a href="https://developer.smartthings.com/docs/edge-device-drivers/zigbee/driver.html">Zigbee Driver Structures</a></li><li><a href="https://developer.smartthings.com/docs/edge-device-drivers/zigbee/defaults.html">Zigbee 默认 Handler</a></li><li><a href="https://developer.smartthings.com/docs/devices/hub-connected/test-your-driver">Edge Driver 测试</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/smartthings-edge-zigbee-driver-development/</id>
    <link href="https://onium.top/posts/smartthings-edge-zigbee-driver-development/"/>
    <published>2026-07-29T02:10:00.000Z</published>
    <summary>
      <![CDATA[<p>SmartThings Edge Driver 在 Hub 本地运行，用 Lua 把 Zigbee 设备行为转换成 SmartThings Capability。兼容工作的核心不是写很多 Handler，而是让 fingerprint、profile、默认处理和设备差异保持一致。</p>]]>
    </summary>
    <title>SmartThings Zigbee 第三方设备兼容：Edge Driver 的匹配、映射与测试</title>
    <updated>2026-07-29T02:49:46.135Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="IEEE 802.15.4" scheme="https://onium.top/tags/ieee-802-15-4/"/>
    <category term="ZCL" scheme="https://onium.top/tags/zcl/"/>
    <category term="Mesh" scheme="https://onium.top/tags/mesh/"/>
    <content>
      <![CDATA[<p>理解 Zigbee 最有效的方法，不是先背命令，而是把“无线、组网、传输、设备管理、应用功能”分层。这样看日志或抓包时，才能知道一条成功信息究竟证明了哪一步。</p><span id="more"></span><h2 id="协议栈分层"><a href="#协议栈分层" class="headerlink" title="协议栈分层"></a>协议栈分层</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">应用逻辑</span><br><span class="line">  │</span><br><span class="line">ZCL：Cluster、Attribute、Command</span><br><span class="line">  │</span><br><span class="line">ZDO / ZDP：设备与服务发现、网络管理</span><br><span class="line">  │</span><br><span class="line">APS：应用数据传输、绑定、组寻址、应用层安全</span><br><span class="line">  │</span><br><span class="line">NWK：组网、路由、网络地址、网络层安全</span><br><span class="line">  │</span><br><span class="line">IEEE 802.15.4 MAC / PHY：信道、帧、确认、射频</span><br></pre></td></tr></table></figure><ul><li>IEEE 802.15.4 提供低速率无线链路；</li><li>NWK 负责 Zigbee Mesh 网络；</li><li>APS 把上层应用消息送到指定设备和 Endpoint；</li><li>ZDO&#x2F;ZDP 提供节点、Endpoint 和服务发现；</li><li>ZCL 定义设备功能的通用数据模型。</li></ul><p>因此，收到 MAC ACK 只说明链路层收到了帧，不代表 NWK 解密、APS 接受或 ZCL 命令处理成功。</p><h2 id="三种逻辑设备角色"><a href="#三种逻辑设备角色" class="headerlink" title="三种逻辑设备角色"></a>三种逻辑设备角色</h2><table><thead><tr><th>角色</th><th>主要职责</th><th>常见限制</th></tr></thead><tbody><tr><td>Coordinator</td><td>建立网络，通常也是集中式网络的 Trust Center</td><td>一个 Zigbee 网络只有一个 Coordinator</td></tr><tr><td>Router</td><td>转发报文并允许子设备接入</td><td>通常需要保持接收能力</td></tr><tr><td>End Device</td><td>通过父节点通信，不为其他节点路由</td><td>可设计成休眠设备</td></tr></tbody></table><p>Coordinator 是网络形成时的角色；网络形成后，Mesh 路由并不要求所有报文都经过它。Router 或 Coordinator 都可以成为 End Device 的父节点。</p><h2 id="地址、Endpoint-与设备功能"><a href="#地址、Endpoint-与设备功能" class="headerlink" title="地址、Endpoint 与设备功能"></a>地址、Endpoint 与设备功能</h2><p>一个 Zigbee 节点通常同时涉及：</p><ul><li>EUI-64：设备的全局扩展地址；</li><li>16 位 NWK 地址：加入网络后使用的短地址，可能变化；</li><li>PAN ID &#x2F; Extended PAN ID：识别网络；</li><li>Endpoint：节点内部的应用端点；</li><li>Profile ID 与 Device ID：声明应用配置和设备类型；</li><li>Cluster：Endpoint 提供或使用的标准功能。</li></ul><p>排障时不要把短地址当作永久身份。跨重启、离网重入或地址冲突处理后，应使用 EUI-64、时间线和设备公告重新确认节点。</p><h2 id="Cluster、Attribute-与-Command"><a href="#Cluster、Attribute-与-Command" class="headerlink" title="Cluster、Attribute 与 Command"></a>Cluster、Attribute 与 Command</h2><p>ZCL 把设备能力拆成 Cluster：</p><ul><li>Server 保存状态、提供属性或接收命令；</li><li>Client 发起命令或消费 Server 产生的信息；</li><li>Attribute 表示状态或配置；</li><li>Command 表示一次操作或协议动作；</li><li>Reporting 让属性按配置主动上报。</li></ul><p>同一个 Cluster ID 的 Server 和 Client 是两个方向，不能因为 Endpoint 列出了 Cluster 就认为双向能力都存在。</p><h2 id="单播、广播、组播与绑定"><a href="#单播、广播、组播与绑定" class="headerlink" title="单播、广播、组播与绑定"></a>单播、广播、组播与绑定</h2><ul><li>单播：发送给一个目标节点；</li><li>广播：发送给一类或全部节点，成本较高；</li><li>组播：发送给 Group ID 对应的一组 Endpoint；</li><li>Binding：在源 Endpoint 中保存逻辑目标，使应用不必每次指定完整目的地址。</li></ul><p>广播不是“更可靠的单播”。它会增加全网负载，且不同广播范围、重试和确认语义并不相同。</p><h2 id="一条应用消息经过什么"><a href="#一条应用消息经过什么" class="headerlink" title="一条应用消息经过什么"></a>一条应用消息经过什么</h2><p>以属性上报为例：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">传感器状态变化</span><br><span class="line">  -&gt; ZCL 生成 Report Attributes</span><br><span class="line">  -&gt; APS 选择目的 Endpoint、绑定或地址</span><br><span class="line">  -&gt; NWK 选择下一跳并进行网络层保护</span><br><span class="line">  -&gt; MAC 在当前信道发送</span><br><span class="line">  -&gt; 目标逐层解密、分发并处理</span><br></pre></td></tr></table></figure><p>每一层都有独立失败点。可靠分析应记录：</p><ol><li>应用是否生成消息；</li><li>APS 是否接受发送请求；</li><li>NWK 是否找到路由；</li><li>MAC 是否发出并收到确认；</li><li>对端是否通过安全校验；</li><li>对端 Endpoint 与 Cluster 是否接受；</li><li>应用状态是否真正改变。</li></ol><h2 id="规范边界"><a href="#规范边界" class="headerlink" title="规范边界"></a>规范边界</h2><p>Zigbee 仍在演进。学习基础概念可以使用公开资料，但实现和认证必须冻结对应的 Zigbee Core、BDB、ZCL、Device Type Library、Errata、PICS 和测试规范，不能把不同 Revision 的要求拼在一起。</p><p>可从 <a href="https://csa-iot.org/all-solutions/zigbee/">Zigbee 官方概览</a>、<a href="https://csa-iot.org/all-solutions/zigbee/zigbee-faq/">Zigbee FAQ</a> 和 <a href="https://csa-iot.org/developer-resource/specifications-download-request/">CSA 规范下载入口</a>继续阅读。</p>]]>
    </content>
    <id>https://onium.top/posts/zigbee-foundations/</id>
    <link href="https://onium.top/posts/zigbee-foundations/"/>
    <published>2026-07-28T13:30:00.000Z</published>
    <summary>
      <![CDATA[<p>理解 Zigbee 最有效的方法，不是先背命令，而是把“无线、组网、传输、设备管理、应用功能”分层。这样看日志或抓包时，才能知道一条成功信息究竟证明了哪一步。</p>]]>
    </summary>
    <title>Zigbee 基础概念：从无线帧到 Endpoint 与 Cluster</title>
    <updated>2026-07-28T13:36:40.299Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Commissioning" scheme="https://onium.top/tags/commissioning/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="BDB" scheme="https://onium.top/tags/bdb/"/>
    <category term="问题排查" scheme="https://onium.top/tags/%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5/"/>
    <content>
      <![CDATA[<p>“设备已经入网”经常被过早下结论。扫描到网络、拿到短地址、收到 Network Key、完成 Trust Center Link Key 交换和网关识别出应用能力，是不同阶段。</p><span id="more"></span><h2 id="先区分三条路径"><a href="#先区分三条路径" class="headerlink" title="先区分三条路径"></a>先区分三条路径</h2><ul><li>首次加入：Factory New 设备通过 Network Steering 寻找允许加入的网络；</li><li>Rejoin：设备保留网络信息后重新连接，流程和安全条件不同；</li><li>Touchlink：近距离发现和引导入网的另一套 commissioning 方法。</li></ul><p>本文讨论经典的首次 Network Steering。实际实现应以目标 BDB、Zigbee Core 和安全策略版本为准。</p><h2 id="阶段一：打开网络与扫描"><a href="#阶段一：打开网络与扫描" class="headerlink" title="阶段一：打开网络与扫描"></a>阶段一：打开网络与扫描</h2><p>网络侧进入 Permit Join 状态。待入网设备在配置的主信道集扫描 Beacon，必要时再扫描次信道集，并根据网络容量、信号和安全信息选择候选网络。</p><p>这一阶段的成功锚点是：</p><ul><li>找到目标 PAN；</li><li>目标网络允许加入；</li><li>设备选择了预期信道与 Extended PAN ID。</li></ul><p>只看到 Beacon 不能证明设备已经发起关联。</p><h2 id="阶段二：关联并获得网络地址"><a href="#阶段二：关联并获得网络地址" class="headerlink" title="阶段二：关联并获得网络地址"></a>阶段二：关联并获得网络地址</h2><p>设备向父节点候选发起关联，父节点返回状态和 16 位网络地址。此后设备具备拓扑位置，但还不代表已经拿到可用的安全材料。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Scan</span><br><span class="line">  -&gt; Select network</span><br><span class="line">  -&gt; Association Request</span><br><span class="line">  -&gt; Association Response</span><br><span class="line">  -&gt; Short address assigned</span><br></pre></td></tr></table></figure><p>MAC 层关联成功只证明链路和父子关系初步建立。</p><h2 id="阶段三：安全准入与-Network-Key"><a href="#阶段三：安全准入与-Network-Key" class="headerlink" title="阶段三：安全准入与 Network Key"></a>阶段三：安全准入与 Network Key</h2><p>集中式安全网络中，Trust Center 决定设备是否被接纳，并通过受保护的密钥传输把 Network Key 交给新设备。设备必须：</p><ol><li>接收到正确的 Transport Key；</li><li>使用匹配的预配置或 install-code 派生 Link Key 验证并解密；</li><li>安装正确的 Network Key 及其序列号；</li><li>启动受保护的 NWK 通信。</li></ol><p>所以“Transport Key 已发出”不等于“设备已安装 Network Key”。决定性证据在接收端的 APS 安全处理和密钥安装结果。</p><h2 id="阶段四：设备公告与-Trust-Center-Link-Key"><a href="#阶段四：设备公告与-Trust-Center-Link-Key" class="headerlink" title="阶段四：设备公告与 Trust Center Link Key"></a>阶段四：设备公告与 Trust Center Link Key</h2><p>设备通常会发送 Device Announcement，让网络获知其地址映射。根据 BDB 版本和 Trust Center 策略，后续还可能执行 Trust Center Link Key 的更新或交换。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Network Key installed</span><br><span class="line">  -&gt; secure network communication</span><br><span class="line">  -&gt; Device Announcement</span><br><span class="line">  -&gt; Trust Center Link Key procedure</span><br><span class="line">  -&gt; commissioning complete</span><br></pre></td></tr></table></figure><p>如果日志显示网络层通信已经成功，但 BDB 最终报告 Trust Center Link Key 交换失败，就不应把问题归回“没有收到 Network Key”。</p><h2 id="阶段五：应用发现"><a href="#阶段五：应用发现" class="headerlink" title="阶段五：应用发现"></a>阶段五：应用发现</h2><p>网络接入完成后，控制端通常还会：</p><ul><li>查询 Node Descriptor；</li><li>查询 Active Endpoints；</li><li>读取 Simple Descriptor；</li><li>读取 Basic 属性；</li><li>配置 Reporting；</li><li>建立 Binding 或执行专用 Cluster 初始化。</li></ul><p>设备在网络里可达，不等于已经被生态完整识别。应用发现失败应与基础入网失败分开记录。</p><h2 id="推荐排障时间线"><a href="#推荐排障时间线" class="headerlink" title="推荐排障时间线"></a>推荐排障时间线</h2><table><thead><tr><th>阶段</th><th>最小成功证据</th><th>常见误判</th></tr></thead><tbody><tr><td>扫描</td><td>选择目标网络</td><td>把看到 Beacon 当作入网</td></tr><tr><td>关联</td><td>成功状态与短地址</td><td>把 MAC ACK 当作安全成功</td></tr><tr><td>密钥传输</td><td>接收端安装 Network Key</td><td>只看发送端“delivered”</td></tr><tr><td>安全通信</td><td>能发送并接收受保护 NWK 帧</td><td>不检查 frame counter 与 key sequence</td></tr><tr><td>TCLK</td><td>BDB 明确完成</td><td>把 Network Key 成功等同 TCLK 成功</td></tr><tr><td>应用发现</td><td>Endpoint、Cluster、属性交互完成</td><td>把可 ping 或可寻址当作设备可用</td></tr></tbody></table><h2 id="抓包与日志怎么对齐"><a href="#抓包与日志怎么对齐" class="headerlink" title="抓包与日志怎么对齐"></a>抓包与日志怎么对齐</h2><p>记录统一时间基准，并同时保留：</p><ul><li>设备串口日志；</li><li>Coordinator &#x2F; Trust Center 日志；</li><li>802.15.4 抓包；</li><li>测试工具或网关事件；</li><li>固件版本和本次安全策略。</li></ul><p>密钥、install code、地址和抓包解密材料只应在授权的本地环境使用，不应复制到公开问题单或文章。</p><p>规范入口可参考 <a href="https://csa-iot.org/developer-resource/specifications-download-request/">CSA Zigbee 规范下载页</a>；认证自测还应使用目标版本的 BDB PICS 和正式测试规范。</p>]]>
    </content>
    <id>https://onium.top/posts/zigbee-network-joining-flow/</id>
    <link href="https://onium.top/posts/zigbee-network-joining-flow/"/>
    <published>2026-07-28T13:20:00.000Z</published>
    <summary>
      <![CDATA[<p>“设备已经入网”经常被过早下结论。扫描到网络、拿到短地址、收到 Network Key、完成 Trust Center Link Key 交换和网关识别出应用能力，是不同阶段。</p>]]>
    </summary>
    <title>Zigbee 入网流程：从 Network Steering 到可用设备</title>
    <updated>2026-07-28T13:36:40.300Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="Security" scheme="https://onium.top/tags/security/"/>
    <category term="Network Key" scheme="https://onium.top/tags/network-key/"/>
    <category term="Link Key" scheme="https://onium.top/tags/link-key/"/>
    <content>
      <![CDATA[<p>Zigbee 排障中最常见的安全误区，是把所有 128-bit Key 都理解成同一种东西。Key 的长度相同，不代表作用层、通信对象、生命周期和泄露影响相同。</p><span id="more"></span><h2 id="一张作用域表"><a href="#一张作用域表" class="headerlink" title="一张作用域表"></a>一张作用域表</h2><table><thead><tr><th>Key</th><th>典型持有者</th><th>保护范围</th><th>主要用途</th></tr></thead><tbody><tr><td>Network Key</td><td>网络内节点</td><td>整个 Zigbee 网络的 NWK 层</td><td>日常网络层帧保护</td></tr><tr><td>Trust Center Link Key</td><td>单个设备与 Trust Center</td><td>两个节点之间的 APS 层</td><td>安全管理、密钥传输与认证</td></tr><tr><td>Install-code 派生 Key</td><td>新设备与 Trust Center</td><td>初次准入阶段</td><td>为设备提供唯一的初始信任</td></tr><tr><td>Application Link Key</td><td>两个应用节点</td><td>端到端 APS 层</td><td>保护特定设备间应用通信</td></tr><tr><td>Touchlink commissioning Key</td><td>支持 Touchlink 的设备</td><td>Touchlink 入网阶段</td><td>保护网络参数传输</td></tr><tr><td>Green Power Key</td><td>Green Power 角色</td><td>Green Power 子系统</td><td>保护对应的精简设备通信</td></tr></tbody></table><p>表格描述的是概念边界。具体必选能力和密钥派生方法必须回到目标 Zigbee Core、BDB、ZCL、Green Power 与安全策略版本确认。</p><h2 id="Network-Key"><a href="#Network-Key" class="headerlink" title="Network Key"></a>Network Key</h2><p>Network Key 是网络范围的共享密钥，主要用于 NWK 层的机密性、完整性和重放保护。它让节点能够参与正常 Zigbee 网络通信。</p><p>要点：</p><ul><li>同一时刻会有活动 Key Sequence；</li><li>网络可以执行 Network Key Update 和 Switch；</li><li>拿到 Network Key 不等于拥有与 Trust Center 的唯一信任关系；</li><li>Network Key 泄露的影响通常覆盖整个网络。</li></ul><p>抓包能用 Network Key 解密 NWK 帧，也不代表内部 APS 负载一定能继续解密。</p><h2 id="Trust-Center-Link-Key"><a href="#Trust-Center-Link-Key" class="headerlink" title="Trust Center Link Key"></a>Trust Center Link Key</h2><p>Trust Center Link Key 是设备与 Trust Center 之间的 APS Link Key，用于安全管理和特定 APS 加密流程。</p><p>它可能经历：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">初始 bootstrap key</span><br><span class="line">  -&gt; 安全加入</span><br><span class="line">  -&gt; Trust Center Link Key 更新或交换</span><br><span class="line">  -&gt; 唯一设备级 TCLK</span><br></pre></td></tr></table></figure><p>具体路径由 BDB 版本、设备能力和 Trust Center 策略决定。调试时要分开记录“初始 Key 可用”和“最终 TCLK 交换完成”。</p><h2 id="Install-code-的位置"><a href="#Install-code-的位置" class="headerlink" title="Install code 的位置"></a>Install code 的位置</h2><p>Install code 本身不是日常 NWK 通信使用的 Network Key。它经过规范定义的处理后，形成设备唯一的初始 Link Key，用于安全加入。</p><p>它改善了共享 bootstrap key 的风险，但同时要求：</p><ul><li>生产、标签或扫码数据正确绑定到设备；</li><li>Trust Center 预先获得匹配信息；</li><li>长度、校验和、字节序与派生过程一致；</li><li>测试数据不能进入量产。</li></ul><p>任何 install code、派生 Key 或二维码内容都不应出现在公开日志中。</p><h2 id="Application-Link-Key"><a href="#Application-Link-Key" class="headerlink" title="Application Link Key"></a>Application Link Key</h2><p>Application Link Key 用于两个应用节点之间的端到端 APS 安全。它不能替代 Network Key，因为 Zigbee 路由仍依赖受保护的 NWK 层；它也不应被笼统称为 TCLK，因为通信对端可能不是 Trust Center。</p><p>分析加密帧时可按顺序判断：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">MAC frame</span><br><span class="line">  -&gt; NWK security：Network Key</span><br><span class="line">  -&gt; APS security：对应 Link Key</span><br><span class="line">  -&gt; ZCL payload</span><br></pre></td></tr></table></figure><h2 id="全局-bootstrap-key-为什么要谨慎"><a href="#全局-bootstrap-key-为什么要谨慎" class="headerlink" title="全局 bootstrap key 为什么要谨慎"></a>全局 bootstrap key 为什么要谨慎</h2><p>某些兼容路径使用规范定义的全局共享初始 Link Key。因为它不是每台设备唯一的秘密，安全强度依赖后续策略，例如尽快升级到唯一 TCLK、限制 Permit Join 时间和执行设备鉴权。</p><p>公开文章无需、也不应抄写这个 Key 的实际值。知道“它是共享 bootstrap 材料”已经足够用于设计和排障。</p><h2 id="Touchlink-与-Green-Power-不要混入普通路径"><a href="#Touchlink-与-Green-Power-不要混入普通路径" class="headerlink" title="Touchlink 与 Green Power 不要混入普通路径"></a>Touchlink 与 Green Power 不要混入普通路径</h2><p>Touchlink commissioning Key 服务于 Touchlink 的网络参数交换；Green Power 还有自己的共享、组或单设备安全材料。它们不应被当成普通 Zigbee 设备的 Network Key 或 TCLK。</p><h2 id="排障时至少记录什么"><a href="#排障时至少记录什么" class="headerlink" title="排障时至少记录什么"></a>排障时至少记录什么</h2><p>不要记录 Key 内容，而是记录元数据：</p><ul><li>安全层：NWK 还是 APS；</li><li>Key 类型和逻辑槽位；</li><li>Key Sequence；</li><li>对端角色；</li><li>frame counter 是否前进；</li><li>解密、MIC 验证和重放检查结果；</li><li>Key 安装、更新、切换或删除事件。</li></ul><p>“发送成功”只能证明本端协议栈接收了请求或下层完成传输；只有对端安全层验证通过，才能证明使用了匹配的 Key。</p><p>可从 <a href="https://csa-iot.org/developer-resource/specifications-download-request/">Zigbee 官方规范入口</a>获取当前公开规范。认证或量产策略必须再与芯片平台安全指南及实验室冻结版本核对。</p>]]>
    </content>
    <id>https://onium.top/posts/zigbee-security-key-scope/</id>
    <link href="https://onium.top/posts/zigbee-security-key-scope/"/>
    <published>2026-07-28T13:10:00.000Z</published>
    <summary>
      <![CDATA[<p>Zigbee 排障中最常见的安全误区，是把所有 128-bit Key 都理解成同一种东西。Key 的长度相同，不代表作用层、通信对象、生命周期和泄露影响相同。</p>]]>
    </summary>
    <title>Zigbee 各类 Key 的作用范围：不要把 Network Key 和 Link Key 混为一谈</title>
    <updated>2026-07-28T13:36:40.300Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="Trust Center" scheme="https://onium.top/tags/trust-center/"/>
    <category term="集中式网络" scheme="https://onium.top/tags/%E9%9B%86%E4%B8%AD%E5%BC%8F%E7%BD%91%E7%BB%9C/"/>
    <category term="分布式网络" scheme="https://onium.top/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E7%BD%91%E7%BB%9C/"/>
    <content>
      <![CDATA[<p>“集中式”和“分布式”首先描述安全与网络管理模型，不是简单描述数据包是否经过 Coordinator。集中式 Zigbee 网络同样可以由 Router 之间直接多跳转发。</p><span id="more"></span><h2 id="核心对比"><a href="#核心对比" class="headerlink" title="核心对比"></a>核心对比</h2><table><thead><tr><th>维度</th><th>集中式安全网络</th><th>分布式安全网络</th></tr></thead><tbody><tr><td>信任中心</td><td>有 Trust Center</td><td>没有中央 Trust Center</td></tr><tr><td>准入决策</td><td>由 Trust Center 控制</td><td>由分布式网络规则协同</td></tr><tr><td>Link Key</td><td>可建立设备唯一 TCLK</td><td>不依赖中央 TCLK 模型</td></tr><tr><td>网络管理</td><td>关键安全策略集中</td><td>形成和管理更分散</td></tr><tr><td>常见场景</td><td>网关型生态、统一管理</td><td>特定照明或去中心化场景</td></tr></tbody></table><p>这只是概念表。允许的设备类型、加入方式、密钥交换和兼容条件随 Zigbee&#x2F;BDB 版本变化，认证时必须看冻结规范。</p><h2 id="集中式网络"><a href="#集中式网络" class="headerlink" title="集中式网络"></a>集中式网络</h2><p>集中式网络通常由 Coordinator 建网并承担 Trust Center 角色。Trust Center 负责：</p><ul><li>决定是否允许新设备加入；</li><li>管理初始信任与设备鉴权；</li><li>传输或更新 Network Key；</li><li>管理设备级 Trust Center Link Key；</li><li>移除不再可信的设备。</li></ul><p>路由仍由 Mesh 完成。设备 A 到设备 B 的正常业务帧不必每次穿过 Trust Center。</p><h2 id="分布式网络"><a href="#分布式网络" class="headerlink" title="分布式网络"></a>分布式网络</h2><p>分布式网络没有一个持续承担中央信任决策的 Trust Center。形成网络、扩展网络和安全管理依赖分布式规则及共享的安全基础。</p><p>它减少了对中央角色的依赖，但不代表：</p><ul><li>没有 Network Key；</li><li>没有加密和重放保护；</li><li>任意设备都可无条件加入；</li><li>与集中式设备天然完全兼容。</li></ul><p>分布式是另一套受规范约束的安全模型，不是“关闭安全”。</p><h2 id="Coordinator、Trust-Center-与-Router-的关系"><a href="#Coordinator、Trust-Center-与-Router-的关系" class="headerlink" title="Coordinator、Trust Center 与 Router 的关系"></a>Coordinator、Trust Center 与 Router 的关系</h2><p>三个概念容易混淆：</p><ul><li>Coordinator：形成 PAN 的逻辑设备；</li><li>Trust Center：集中式安全网络中的信任管理角色；</li><li>Router：参与 Mesh 路由并可能允许子节点关联。</li></ul><p>集中式网络中 Coordinator 通常兼任 Trust Center，但这不等于它是所有应用报文的中心转发器。</p><h2 id="选择时看什么"><a href="#选择时看什么" class="headerlink" title="选择时看什么"></a>选择时看什么</h2><ol><li>目标生态是否要求中央 Trust Center；</li><li>是否需要 install code 和设备唯一 TCLK；</li><li>目标设备及历史 Profile 是否支持该网络类型；</li><li>是否需要 Touchlink；</li><li>网络形成、备份、迁移与恢复策略；</li><li>对失窃节点、共享 bootstrap 材料和密钥轮换的风险接受度；</li><li>对应认证计划和 PICS 允许什么。</li></ol><p>不要只因为“想避免单点故障”就选择分布式网络。集中式安全角色与 Mesh 数据路径是不同问题；Zigbee Router 的多路径转发仍可提供网络韧性。</p><h2 id="抓包如何识别"><a href="#抓包如何识别" class="headerlink" title="抓包如何识别"></a>抓包如何识别</h2><p>单靠一帧普通 NWK 数据通常不足以判断网络模型。应结合：</p><ul><li>网络形成日志；</li><li>Trust Center 地址与策略；</li><li>Beacon 或网络安全相关信息；</li><li>加入时的密钥传输路径；</li><li>TCLK 交换行为；</li><li>BDB 配置与 PICS。</li></ul><h2 id="版本与兼容边界"><a href="#版本与兼容边界" class="headerlink" title="版本与兼容边界"></a>版本与兼容边界</h2><p>旧的 Zigbee Light Link、Home Automation 与 Zigbee 3.x&#x2F;4.x 之间存在特定兼容规则，不能用“都是 Zigbee”代替逐项核对。CSA 的 <a href="https://csa-iot.org/wp-content/uploads/2021/12/04-2017-Interoperability-ORIGINAL-White-Paper-Final-Musa-and-Shashank-1.pdf">互操作白皮书</a>可帮助理解历史关系；当前实现仍应以 <a href="https://csa-iot.org/developer-resource/specifications-download-request/">CSA 规范下载入口</a>和认证实验室确认的版本为准。</p>]]>
    </content>
    <id>https://onium.top/posts/zigbee-centralized-distributed-networks/</id>
    <link href="https://onium.top/posts/zigbee-centralized-distributed-networks/"/>
    <published>2026-07-28T13:00:00.000Z</published>
    <summary>
      <![CDATA[<p>“集中式”和“分布式”首先描述安全与网络管理模型，不是简单描述数据包是否经过 Coordinator。集中式 Zigbee 网络同样可以由 Router 之间直接多跳转发。</p>]]>
    </summary>
    <title>Zigbee 集中式网络与分布式网络：差异主要在信任模型</title>
    <updated>2026-07-28T13:36:40.300Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Commissioning" scheme="https://onium.top/tags/commissioning/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="ZCL" scheme="https://onium.top/tags/zcl/"/>
    <category term="Touchlink" scheme="https://onium.top/tags/touchlink/"/>
    <content>
      <![CDATA[<p>Touchlink 是 Zigbee 的一种近距离 commissioning 机制，最初广泛用于照明设备。它不是普通的 Network Steering，也不是“按键后信号强就自动入网”这么简单。</p><span id="more"></span><h2 id="两个角色"><a href="#两个角色" class="headerlink" title="两个角色"></a>两个角色</h2><ul><li>Initiator：发起 Touchlink 的控制设备；</li><li>Target：被发现、识别、复位或加入网络的设备。</li></ul><p>两者通过 Touchlink Commissioning Cluster 交互。是否支持某条命令、某种设备角色和网络类型，应由目标版本的 PICS 决定。</p><h2 id="高层流程"><a href="#高层流程" class="headerlink" title="高层流程"></a>高层流程</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Initiator 扫描信道</span><br><span class="line">  -&gt; Scan Request</span><br><span class="line">  &lt;- Scan Response</span><br><span class="line">  -&gt; 根据距离、能力和状态选择 Target</span><br><span class="line">  -&gt; 可选 Identify / Device Information</span><br><span class="line">  -&gt; Network Start 或 Network Join</span><br><span class="line">  -&gt; 受保护地传输网络参数</span><br><span class="line">  -&gt; Target 切换信道并启动网络</span><br><span class="line">  -&gt; 后续应用发现与配置</span><br></pre></td></tr></table></figure><p>Touchlink 还可能提供 Reset to Factory New 等管理动作，因此触发条件和物理在场约束非常重要。</p><h2 id="扫描与“近距离”判断"><a href="#扫描与“近距离”判断" class="headerlink" title="扫描与“近距离”判断"></a>扫描与“近距离”判断</h2><p>Initiator 会在规定信道上发送扫描请求，Target 返回能力、网络状态等信息。实现通常根据接收信号强度或协议定义的 proximity 条件筛选目标。</p><p>RSSI 只是一项输入：</p><ul><li>不同硬件的接收链路和校准不同；</li><li>环境反射会造成波动；</li><li>强信号不等于身份可信；</li><li>过宽阈值可能误选附近其他设备。</li></ul><p>因此还应结合用户动作、设备状态、响应事务标识和超时窗口。</p><h2 id="Identify-不是入网"><a href="#Identify-不是入网" class="headerlink" title="Identify 不是入网"></a>Identify 不是入网</h2><p>Identify 让用户确认正在操作哪台设备，例如闪灯或执行可见动作。它不表示网络参数已经写入，也不表示 Target 已完成加入。</p><p>推荐成功锚点：</p><ol><li>Scan Response 匹配当前事务；</li><li>选择了唯一目标；</li><li>Identify 行为可被用户确认；</li><li>Network Start&#x2F;Join 响应成功；</li><li>Target 在目标信道启动；</li><li>后续受保护 Zigbee 通信成功。</li></ol><h2 id="网络参数传输"><a href="#网络参数传输" class="headerlink" title="网络参数传输"></a>网络参数传输</h2><p>Touchlink 使用专门的 commissioning 安全过程保护 Network Key 等网络参数。其 commissioning Key 只服务于这一阶段，不应与日常 NWK 使用的 Network Key 混淆。</p><p>公开日志中不应输出：</p><ul><li>commissioning Key；</li><li>Network Key；</li><li>未脱敏的设备唯一地址；</li><li>可用于复现实网加入的数据。</li></ul><h2 id="与经典加入的区别"><a href="#与经典加入的区别" class="headerlink" title="与经典加入的区别"></a>与经典加入的区别</h2><table><thead><tr><th>项目</th><th>Touchlink</th><th>Network Steering</th></tr></thead><tbody><tr><td>发现方式</td><td>主动近距离扫描目标</td><td>扫描允许加入的网络</td></tr><tr><td>主要角色</td><td>Initiator &#x2F; Target</td><td>Trust Center、父节点、Joiner</td></tr><tr><td>典型触发</td><td>用户近距离操作</td><td>设备进入入网模式</td></tr><tr><td>安全路径</td><td>Touchlink commissioning 安全</td><td>BDB 加入与 Link Key 策略</td></tr><tr><td>后续结果</td><td>建网、加入或管理动作</td><td>加入现有网络</td></tr></tbody></table><p>Touchlink 成功后仍需要正常 Zigbee 网络和应用层交互；它不是独立的日常通信协议。</p><h2 id="常见失败分类"><a href="#常见失败分类" class="headerlink" title="常见失败分类"></a>常见失败分类</h2><ul><li>扫描不到：信道集、时序、角色能力或距离门限；</li><li>响应被丢弃：事务标识、重复帧或状态不匹配；</li><li>Identify 成功但 Join 失败：网络状态、目标角色或安全参数；</li><li>参数写入后未启动：信道切换、持久化或状态机；</li><li>入网后不可用：Endpoint 发现、Cluster、binding 或 reporting；</li><li>Reset 行为异常：Factory New 判定和持久化清理不完整。</li></ul><h2 id="规范边界"><a href="#规范边界" class="headerlink" title="规范边界"></a>规范边界</h2><p>旧 ZCL 中可以找到 Touchlink Commissioning Cluster，但认证实现不能只照抄旧章节。应同时冻结目标 Zigbee Core、BDB、ZCL、PICS、Errata 和测试用例，并确认当前认证计划是否接受所选 Touchlink 能力。</p><p>公开入口包括 <a href="https://csa-iot.org/developer-resource/specifications-download-request/">CSA Zigbee 规范下载页</a>与 <a href="https://csa-iot.org/certification/tools/">Zigbee 认证工具页</a>。</p>]]>
    </content>
    <id>https://onium.top/posts/zigbee-touchlink-commissioning/</id>
    <link href="https://onium.top/posts/zigbee-touchlink-commissioning/"/>
    <published>2026-07-28T12:50:00.000Z</published>
    <summary>
      <![CDATA[<p>Touchlink 是 Zigbee 的一种近距离 commissioning 机制，最初广泛用于照明设备。它不是普通的 Network Steering，也不是“按键后信号强就自动入网”这么简单。</p>]]>
    </summary>
    <title>Zigbee Touchlink 流程：近距离发现、识别与入网</title>
    <updated>2026-07-28T13:36:40.300Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="认证实践" scheme="https://onium.top/categories/%E8%AE%A4%E8%AF%81%E5%AE%9E%E8%B7%B5/"/>
    <category term="PICS" scheme="https://onium.top/tags/pics/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="Zigbee 3.0" scheme="https://onium.top/tags/zigbee-3-0/"/>
    <category term="ZUTH" scheme="https://onium.top/tags/zuth/"/>
    <content>
      <![CDATA[<p>认证自测的目标不是证明“功能大致能用”，而是在送测前尽量复现正式测试的输入、声明、环境和判定方式，提前找出会阻断认证的问题。</p><span id="more"></span><h2 id="第一步不是运行工具"><a href="#第一步不是运行工具" class="headerlink" title="第一步不是运行工具"></a>第一步不是运行工具</h2><p>先向 CSA 或授权实验室确认并冻结：</p><ul><li>认证计划和 Zigbee 版本；</li><li>Zigbee Core &#x2F; PRO、BDB、ZCL、Device Type Library；</li><li>Approved Errata；</li><li>PICS &#x2F; PIXIT 模板；</li><li>Test Specification 与测试用例版本；</li><li>ZUTH、脚本、dongle 和固件版本。</li></ul><p>“Zigbee 3.0”是一个过于宽泛的标签。公开工具可能同时保留多个 BDB、ZCL 和 PRO 输入；不能自行把最新版文档和旧测试脚本拼在一起。</p><h2 id="建立声明矩阵"><a href="#建立声明矩阵" class="headerlink" title="建立声明矩阵"></a>建立声明矩阵</h2><p>从每个 Endpoint 展开：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Profile ID / Device ID</span><br><span class="line">  -&gt; Server / Client Cluster</span><br><span class="line">  -&gt; Mandatory / Optional / Conditional</span><br><span class="line">  -&gt; Attribute 类型、范围、默认值和权限</span><br><span class="line">  -&gt; Reporting</span><br><span class="line">  -&gt; Commands Received / Generated</span><br><span class="line">  -&gt; PICS / PIXIT</span><br><span class="line">  -&gt; 对应测试用例</span><br></pre></td></tr></table></figure><p>一旦实现了 Optional 能力，它通常也会进入声明和测试范围。为了减少测试，不应把已经对外可见的能力错误标成不支持。</p><h2 id="四层自测"><a href="#四层自测" class="headerlink" title="四层自测"></a>四层自测</h2><h3 id="静态核对"><a href="#静态核对" class="headerlink" title="静态核对"></a>静态核对</h3><ul><li>Simple Descriptor 与实际 Cluster 注册一致；</li><li>ClusterRevision 和 ZCLVersion 对应冻结版本；</li><li>属性类型、默认值、访问权限和范围正确；</li><li>接收与发送命令方向正确；</li><li>PICS 与固件能力一致；</li><li>认证配置确实进入最终镜像。</li></ul><h3 id="功能与状态机"><a href="#功能与状态机" class="headerlink" title="功能与状态机"></a>功能与状态机</h3><ul><li>标准读写、命令和 reporting；</li><li>默认响应与异常状态；</li><li>初始化、重启、掉电与恢复出厂；</li><li>入网、退网、rejoin、换父与丢网恢复；</li><li>binding、group、scene 等已声明能力；</li><li>OTA、低电量和持久化边界。</li></ul><h3 id="安全与-BDB"><a href="#安全与-BDB" class="headerlink" title="安全与 BDB"></a>安全与 BDB</h3><ul><li>Network Steering 和 Permit Join；</li><li>install-code 策略；</li><li>Network Key 安装、更新和切换；</li><li>Trust Center Link Key 流程；</li><li>frame counter 与重放拒绝；</li><li>集中式或分布式网络声明；</li><li>Touchlink 等可选 commissioning 能力。</li></ul><h3 id="正式工具预跑"><a href="#正式工具预跑" class="headerlink" title="正式工具预跑"></a>正式工具预跑</h3><p>CSA 的 ZUTH 是 Zigbee 正式认证测试工具，也向成员提供预认证测试能力。导入已审查的 PICS，运行所有被选择用例，并保留原始结果。</p><h2 id="Sleepy-End-Device-专项"><a href="#Sleepy-End-Device-专项" class="headerlink" title="Sleepy End Device 专项"></a>Sleepy End Device 专项</h2><p>低功耗设备常在正式测试中暴露时序问题：</p><ul><li>Poll Control 行为；</li><li>Fast Poll 窗口；</li><li>父节点缓存与间接传输；</li><li>reporting 延迟；</li><li>enrollment 或 commissioning 期间的接收窗口；</li><li>测试刺激与设备睡眠状态的同步。</li></ul><p>不要通过永久关闭休眠来“通过认证”，除非认证固件与量产行为差异得到明确允许并被记录。</p><h2 id="失败归类"><a href="#失败归类" class="headerlink" title="失败归类"></a>失败归类</h2><table><thead><tr><th>类别</th><th>例子</th><th>下一步证据</th></tr></thead><tbody><tr><td>声明错误</td><td>PICS 与 Endpoint 不一致</td><td>描述符、PICS、构建配置</td></tr><tr><td>协议错误</td><td>命令方向或状态码错误</td><td>空口与 DUT 日志</td></tr><tr><td>时序错误</td><td>超时、休眠错过命令</td><td>统一时间线、poll 日志</td></tr><tr><td>环境错误</td><td>dongle、脚本或版本不匹配</td><td>环境清单与工具日志</td></tr><tr><td>用例解释</td><td>前置条件理解不同</td><td>测试规范、实验室确认</td></tr></tbody></table><p>修复后要回归相关用例集合，不能只重跑最初失败的一步。</p><h2 id="自测证据包"><a href="#自测证据包" class="headerlink" title="自测证据包"></a>自测证据包</h2><p>每轮保存：</p><ul><li>固件版本、源码提交和构建哈希；</li><li>PICS &#x2F; PIXIT；</li><li>环境和工具版本；</li><li>测试用例列表；</li><li>原始 ZUTH 报告；</li><li>DUT、测试端与抓包日志；</li><li>失败分析、修复提交和回归结果；</li><li>尚未验证的限制。</li></ul><p>证据层级必须分开：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">规范要求</span><br><span class="line">  != PICS 声明</span><br><span class="line">  != 静态实现</span><br><span class="line">  != 设备运行通过</span><br><span class="line">  != ZUTH 自测通过</span><br><span class="line">  != 授权实验室通过</span><br><span class="line">  != CSA 正式认证</span><br></pre></td></tr></table></figure><p>可从 <a href="https://csa-iot.org/certification/tools/">CSA 认证工具页</a>获取 PICS Tool 和 ZUTH 说明。当前版本和送测范围仍应由 <a href="https://csa-iot.org/certification/testing-providers/">授权测试机构</a>确认。</p>]]>
    </content>
    <id>https://onium.top/posts/zigbee-3-certification-self-test/</id>
    <link href="https://onium.top/posts/zigbee-3-certification-self-test/"/>
    <published>2026-07-28T12:40:00.000Z</published>
    <summary>
      <![CDATA[<p>认证自测的目标不是证明“功能大致能用”，而是在送测前尽量复现正式测试的输入、声明、环境和判定方式，提前找出会阻断认证的问题。</p>]]>
    </summary>
    <title>Zigbee 3.0 认证自测：从版本冻结到证据包</title>
    <updated>2026-07-28T13:36:40.301Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="认证实践" scheme="https://onium.top/categories/%E8%AE%A4%E8%AF%81%E5%AE%9E%E8%B7%B5/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="Zigbee 3.0" scheme="https://onium.top/tags/zigbee-3-0/"/>
    <category term="认证流程" scheme="https://onium.top/tags/%E8%AE%A4%E8%AF%81%E6%B5%81%E7%A8%8B/"/>
    <category term="CSA" scheme="https://onium.top/tags/csa/"/>
    <content>
      <![CDATA[<p>Zigbee 认证不是“把样机交给实验室，跑完测试就结束”。技术实现、正式测试、申请审核和认证后的变更管理属于不同责任主体。</p><span id="more"></span><h2 id="先确认认证对象"><a href="#先确认认证对象" class="headerlink" title="先确认认证对象"></a>先确认认证对象</h2><p>常见对象包括：</p><ul><li>Compliant Platform：无线芯片、处理器和 Zigbee 协议栈形成的平台基础；</li><li>Certified Product：面向最终用途的完整产品；</li><li>认证转移、产品系列或相似产品路径：是否适用由当前政策决定。</li></ul><p>大多数终端产品以合规平台为基础，但平台证书不会自动覆盖产品的 Endpoint、Device Type、Cluster 和应用行为。</p><h2 id="全流程"><a href="#全流程" class="headerlink" title="全流程"></a>全流程</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">确定产品与市场范围</span><br><span class="line">  -&gt; 确认 CSA 会员与认证路径</span><br><span class="line">  -&gt; 选择合规平台</span><br><span class="line">  -&gt; 冻结规范和测试输入</span><br><span class="line">  -&gt; 完成实现与 PICS / PIXIT</span><br><span class="line">  -&gt; 内部自测</span><br><span class="line">  -&gt; 选择授权测试机构</span><br><span class="line">  -&gt; 正式测试与问题关闭</span><br><span class="line">  -&gt; 提交认证申请与报告</span><br><span class="line">  -&gt; CSA 审核</span><br><span class="line">  -&gt; 证书、公开记录与标志授权</span><br><span class="line">  -&gt; 版本变更与再认证判断</span><br></pre></td></tr></table></figure><h2 id="开发阶段要准备什么"><a href="#开发阶段要准备什么" class="headerlink" title="开发阶段要准备什么"></a>开发阶段要准备什么</h2><p>至少固定以下内容：</p><ul><li>硬件、软件和固件版本；</li><li>合规平台及其证书范围；</li><li>Endpoint、Profile ID、Device ID；</li><li>Server &#x2F; Client Cluster；</li><li>Mandatory、Optional 和 Conditional 能力；</li><li>commissioning、安全与网络类型；</li><li>量产配置和认证配置差异；</li><li>目标生态的附加要求。</li></ul><p>生态认证和 Zigbee 认证是两套范围。通过 CSA Zigbee 认证，不自动代表通过某个商业生态的兼容性认证。</p><h2 id="PICS-与-PIXIT"><a href="#PICS-与-PIXIT" class="headerlink" title="PICS 与 PIXIT"></a>PICS 与 PIXIT</h2><ul><li>PICS 声明实现支持哪些协议能力；</li><li>PIXIT 提供测试所需的实现参数；</li><li>它们驱动用例选择，也是实验室解释行为的依据。</li></ul><p>填写原则是“与被测固件真实能力一致”。少报会导致声明不实，多报会扩大测试范围并暴露未完成能力。</p><h2 id="授权测试机构做什么"><a href="#授权测试机构做什么" class="headerlink" title="授权测试机构做什么"></a>授权测试机构做什么</h2><p>授权测试机构根据冻结的测试计划和 PICS：</p><ul><li>审核样机与文档；</li><li>配置正式测试环境；</li><li>执行必选及已实现可选能力的用例；</li><li>记录偏差和失败；</li><li>在问题关闭后出具正式测试报告。</li></ul><p>测试机构不替代产品团队做 Device Type 设计，也不能用口头经验覆盖规范和 PICS。</p><h2 id="CSA-审核做什么"><a href="#CSA-审核做什么" class="headerlink" title="CSA 审核做什么"></a>CSA 审核做什么</h2><p>正式测试通过后，还需要通过 CSA 的认证工具提交申请材料。审核关注产品身份、声明、测试报告、合规平台和政策要求。批准后，产品才会获得对应证书、公开记录及标志使用资格。</p><p>“实验室测试通过”和“CSA 已正式认证”必须分开表述。</p><h2 id="失败与重测"><a href="#失败与重测" class="headerlink" title="失败与重测"></a>失败与重测</h2><p>出现失败时，建议维护：</p><ol><li>用例、前置条件和失败步骤；</li><li>规范条款与 PICS 项；</li><li>DUT、测试端、抓包时间线；</li><li>根因属于实现、环境还是用例解释；</li><li>修复影响范围；</li><li>实验室确认的重测集合；</li><li>新固件标识和回归结果。</li></ol><p>不要在未与实验室确认前自行判断“只改一行，无需重测”。</p><h2 id="认证后的版本管理"><a href="#认证后的版本管理" class="headerlink" title="认证后的版本管理"></a>认证后的版本管理</h2><p>认证绑定具体产品和版本信息。后续变更应评估：</p><ul><li>协议栈或合规平台升级；</li><li>Device Type、Cluster、属性和命令变化；</li><li>安全策略或 commissioning 变化；</li><li>硬件和射频变化；</li><li>修复是否触及已测试行为；</li><li>是否适用转移、系列、相似或再认证路径。</li></ul><h2 id="当前版本提醒"><a href="#当前版本提醒" class="headerlink" title="当前版本提醒"></a>当前版本提醒</h2><p>截至本文更新时，Zigbee 规范、PICS 和认证工具仍在演进。项目名称里写“Zigbee 3.0”不代表可以自行选择任意历史输入；新申请是否继续采用某个 3.0 组合，应在立项时由 CSA 或授权实验室书面确认。</p><p>官方入口：</p><ul><li><a href="https://csa-iot.org/certification/">CSA Certification</a></li><li><a href="https://csa-iot.org/certification/tools/">认证工具与 ZUTH</a></li><li><a href="https://csa-iot.org/certification/testing-providers/">授权测试机构</a></li><li><a href="https://csa-iot.org/developer-resource/specifications-download-request/">Zigbee 规范下载</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/zigbee-3-certification-process/</id>
    <link href="https://onium.top/posts/zigbee-3-certification-process/"/>
    <published>2026-07-28T12:30:00.000Z</published>
    <summary>
      <![CDATA[<p>Zigbee 认证不是“把样机交给实验室，跑完测试就结束”。技术实现、正式测试、申请审核和认证后的变更管理属于不同责任主体。</p>]]>
    </summary>
    <title>Zigbee 3.0 认证流程：产品、平台、实验室与 CSA 各负责什么</title>
    <updated>2026-07-28T13:36:40.301Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Matter" scheme="https://onium.top/tags/matter/"/>
    <category term="Fabric" scheme="https://onium.top/tags/fabric/"/>
    <category term="Data Model" scheme="https://onium.top/tags/data-model/"/>
    <category term="Commissioning" scheme="https://onium.top/tags/commissioning/"/>
    <content>
      <![CDATA[<p>Matter 是基于 IPv6 的应用层连接标准。它定义的不只是 Cluster，还包括发现、commissioning、安全会话、数据模型、交互模型和设备生命周期。</p><span id="more"></span><h2 id="Matter-在协议栈中的位置"><a href="#Matter-在协议栈中的位置" class="headerlink" title="Matter 在协议栈中的位置"></a>Matter 在协议栈中的位置</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">设备应用</span><br><span class="line">  -&gt; Data Model：Node / Endpoint / Device Type / Cluster</span><br><span class="line">  -&gt; Interaction Model：Read / Write / Invoke / Subscribe</span><br><span class="line">  -&gt; 安全会话：PASE / CASE / Group</span><br><span class="line">  -&gt; IPv6 + UDP</span><br><span class="line">  -&gt; Thread、Wi-Fi 或 Ethernet</span><br></pre></td></tr></table></figure><p>Bluetooth LE 通常作为设备初次 commissioning 的近距离通道，不是 Matter 日常业务通信的 IP 承载。</p><h2 id="Node-与-Endpoint"><a href="#Node-与-Endpoint" class="headerlink" title="Node 与 Endpoint"></a>Node 与 Endpoint</h2><ul><li>Node：一个可寻址的 Matter 逻辑节点；</li><li>Endpoint 0：根端点，承载基础设施和管理 Cluster；</li><li>其他 Endpoint：承载产品功能；</li><li>Device Type：声明 Endpoint 符合哪类标准设备语义；</li><li>Cluster：一组相关属性、命令和事件。</li></ul><p>同一物理设备可以有多个 Endpoint，也可以在一个 Fabric 中对应一个 Node。</p><h2 id="Cluster、Attribute、Command-与-Event"><a href="#Cluster、Attribute、Command-与-Event" class="headerlink" title="Cluster、Attribute、Command 与 Event"></a>Cluster、Attribute、Command 与 Event</h2><table><thead><tr><th>元素</th><th>含义</th></tr></thead><tbody><tr><td>Attribute</td><td>可读取、可订阅，部分可写的状态</td></tr><tr><td>Command</td><td>客户端发起的一次操作</td></tr><tr><td>Event</td><td>带优先级和事件编号的历史事件</td></tr><tr><td>Feature</td><td>Cluster 的可选能力组合</td></tr></tbody></table><p>Interaction Model 统一了：</p><ul><li>Read：读取属性或事件；</li><li>Write：修改允许写入的属性；</li><li>Invoke：调用命令；</li><li>Subscribe：建立持续订阅并接收报告。</li></ul><p>实现了 Cluster 不等于实现了全部可选 Feature。Device Type、Cluster 规范、FeatureMap、全局属性与实际处理逻辑必须一致。</p><h2 id="Fabric-是什么"><a href="#Fabric-是什么" class="headerlink" title="Fabric 是什么"></a>Fabric 是什么</h2><p>Fabric 是一组共享信任域和管理关系的 Matter 节点。一个设备可以加入多个 Fabric，每个 Fabric 拥有独立的：</p><ul><li>Fabric Index；</li><li>Node ID；</li><li>Operational Certificate；</li><li>Group Key 与访问控制状态；</li><li>订阅和管理关系。</li></ul><p>删除一个订阅不等于删除 Fabric；某个 Fabric 断开，也不代表其他 Fabric 必然受影响。</p><h2 id="Commissioning-的阶段"><a href="#Commissioning-的阶段" class="headerlink" title="Commissioning 的阶段"></a>Commissioning 的阶段</h2><p>一个简化流程：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">发现 commissionable device</span><br><span class="line">  -&gt; PASE 建立初始安全通道</span><br><span class="line">  -&gt; Device Attestation</span><br><span class="line">  -&gt; 配置法规与网络参数</span><br><span class="line">  -&gt; 设备进入目标 IP 网络</span><br><span class="line">  -&gt; CSR / AddNOC 建立 Fabric 身份</span><br><span class="line">  -&gt; CASE 可用</span><br><span class="line">  -&gt; Commissioning Complete</span><br></pre></td></tr></table></figure><p>每一步都有独立成功条件：</p><ul><li>BLE 连接成功不等于 PASE 成功；</li><li>Thread Attach 成功不等于 AddNOC 成功；</li><li>AddNOC 成功不等于 Commissioning Complete；</li><li>Commissioning 完成不等于后续 Subscribe 一定稳定。</li></ul><h2 id="PASE-与-CASE"><a href="#PASE-与-CASE" class="headerlink" title="PASE 与 CASE"></a>PASE 与 CASE</h2><ul><li>PASE：基于 setup passcode 建立，主要用于初次 commissioning；</li><li>CASE：基于 Fabric 的 operational credentials，服务于日常单播安全会话；</li><li>Group：服务于一对多组通信。</li></ul><p>setup passcode、证书私钥和 Thread Dataset 都是敏感材料，不应出现在公开日志或仓库。</p><h2 id="发现与地址"><a href="#发现与地址" class="headerlink" title="发现与地址"></a>发现与地址</h2><p>Matter 使用 DNS-SD &#x2F; mDNS 发现节点和服务，并依赖 IPv6 地址。排障时要区分：</p><ul><li>commissionable discovery；</li><li>operational discovery；</li><li>Thread 或 Wi-Fi 网络接入；</li><li>IPv6 路由；</li><li>CASE 会话；</li><li>Interaction Model 操作。</li></ul><p>“mDNS 找不到”可能是网络接口、组播、防火墙或地址作用域问题，不应直接归因于 Cluster。</p><h2 id="从哪里继续学习"><a href="#从哪里继续学习" class="headerlink" title="从哪里继续学习"></a>从哪里继续学习</h2><ul><li><a href="https://github.com/project-chip/connectedhomeip">Matter 官方开源 SDK</a></li><li><a href="https://project-chip.github.io/connectedhomeip-doc/">Matter SDK 文档</a></li><li><a href="https://csa-iot.org/developer-resource/specifications-download-request/">CSA Matter 规范下载入口</a></li></ul><p>SDK 示例用于学习，不自动代表某个具体 Device Type 的完整产品或认证实现。</p>]]>
    </content>
    <id>https://onium.top/posts/matter-foundations/</id>
    <link href="https://onium.top/posts/matter-foundations/"/>
    <published>2026-07-28T12:20:00.000Z</published>
    <summary>
      <![CDATA[<p>Matter 是基于 IPv6 的应用层连接标准。它定义的不只是 Cluster，还包括发现、commissioning、安全会话、数据模型、交互模型和设备生命周期。</p>]]>
    </summary>
    <title>Matter 基础概念：Node、Fabric、Endpoint 与安全会话</title>
    <updated>2026-07-28T13:40:40.993Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Thread" scheme="https://onium.top/tags/thread/"/>
    <category term="IPv6" scheme="https://onium.top/tags/ipv6/"/>
    <category term="OpenThread" scheme="https://onium.top/tags/openthread/"/>
    <category term="Border Router" scheme="https://onium.top/tags/border-router/"/>
    <content>
      <![CDATA[<p>Thread 是建立在 IEEE 802.15.4 之上的低功耗 IPv6 Mesh 网络协议。它提供网络连接能力，但不规定灯、传感器或门锁应该有哪些应用 Cluster。</p><span id="more"></span><h2 id="协议栈位置"><a href="#协议栈位置" class="headerlink" title="协议栈位置"></a>协议栈位置</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Matter 或其他 IP 应用</span><br><span class="line">  -&gt; UDP / IPv6</span><br><span class="line">  -&gt; 6LoWPAN</span><br><span class="line">  -&gt; Thread Mesh Link Establishment 与路由</span><br><span class="line">  -&gt; IEEE 802.15.4 MAC / PHY</span><br></pre></td></tr></table></figure><p>这也是 Matter over Thread 与 Zigbee 的关键区别：Thread 承载 IP，Zigbee 使用自己的 NWK、APS 和应用层体系。</p><h2 id="常见设备角色"><a href="#常见设备角色" class="headerlink" title="常见设备角色"></a>常见设备角色</h2><table><thead><tr><th>角色</th><th>作用</th></tr></thead><tbody><tr><td>Leader</td><td>管理当前 Partition 的路由器集合与网络数据</td></tr><tr><td>Router</td><td>转发 IPv6 数据并允许子设备连接</td></tr><tr><td>Router-Eligible End Device</td><td>当前是 End Device，条件满足时可升级为 Router</td></tr><tr><td>Full End Device</td><td>不承担路由，但保持完整接收能力</td></tr><tr><td>Minimal End Device</td><td>能力更精简，通过父节点通信</td></tr><tr><td>Sleepy End Device</td><td>周期性向父节点 Poll，适合低功耗</td></tr><tr><td>Border Router</td><td>在 Thread Mesh 与相邻 IP 网络之间路由</td></tr></tbody></table><p>Leader 不是所有报文的中央转发器。角色可以变化，网络会根据拓扑自动维护 Router 集合。</p><h2 id="Border-Router-不是应用网关"><a href="#Border-Router-不是应用网关" class="headerlink" title="Border Router 不是应用网关"></a>Border Router 不是应用网关</h2><p>Thread Border Router 的核心职责是 IP 路由和网络数据传播。它让 Thread 节点能与 Wi-Fi&#x2F;Ethernet 等相邻 IPv6 网络通信。</p><p>它通常不负责把一个应用协议翻译成另一个应用协议。Zigbee-to-Matter Bridge 执行的是应用数据模型映射，与 Thread Border Router 是不同角色。</p><p>一个 Thread 网络可以有多个 Border Router，从而减少单点依赖。</p><h2 id="Thread-网络凭据"><a href="#Thread-网络凭据" class="headerlink" title="Thread 网络凭据"></a>Thread 网络凭据</h2><p>Active Operational Dataset 描述 Thread 网络的关键参数，例如信道、PAN 标识、Mesh-Local Prefix 和网络安全材料。</p><p>它是敏感配置：</p><ul><li>不提交到公开仓库；</li><li>不直接粘贴到问题单；</li><li>抓包时只在授权本地环境加载；</li><li>示例使用占位符，不复用真实网络数据。</li></ul><h2 id="IPv6-地址为什么不止一个"><a href="#IPv6-地址为什么不止一个" class="headerlink" title="IPv6 地址为什么不止一个"></a>IPv6 地址为什么不止一个</h2><p>Thread 节点通常具有多类 IPv6 地址：</p><ul><li>Link-Local：邻居链路上的本地通信；</li><li>Mesh-Local EID：拓扑无关的 Mesh 内地址；</li><li>Routing Locator：反映当前拓扑位置；</li><li>Border Router 提供前缀形成的地址；</li><li>多播地址。</li></ul><p>因此，看到一个 IPv6 地址变化不一定代表节点身份变化。排障要结合地址类型、作用域、接口和 Node 身份。</p><h2 id="Attach-的高层流程"><a href="#Attach-的高层流程" class="headerlink" title="Attach 的高层流程"></a>Attach 的高层流程</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">扫描与发现 Partition</span><br><span class="line">  -&gt; 选择父节点</span><br><span class="line">  -&gt; MLE 建立安全邻居关系</span><br><span class="line">  -&gt; 获得网络数据和地址</span><br><span class="line">  -&gt; 成为 Child 或 Router</span><br><span class="line">  -&gt; IPv6 可达</span><br></pre></td></tr></table></figure><p>Thread Attach 成功只证明网络层建立。Matter 还需要 operational discovery、CASE 和应用交互。</p><h2 id="低功耗与父节点"><a href="#低功耗与父节点" class="headerlink" title="低功耗与父节点"></a>低功耗与父节点</h2><p>Sleepy End Device 关闭接收机来省电，通过父节点缓存和周期性 Poll 接收数据。关键参数包括：</p><ul><li>Poll 周期；</li><li>消息等待时间；</li><li>应用订阅的最大间隔；</li><li>重试和父节点切换；</li><li>设备醒来后的处理预算。</li></ul><p>过度延长 Poll 周期会降低功耗，但也可能造成控制延迟、消息过期或 commissioning 超时。</p><h2 id="抓包识别"><a href="#抓包识别" class="headerlink" title="抓包识别"></a>抓包识别</h2><p>Thread 抓包常见层级包括：</p><ul><li>IEEE 802.15.4；</li><li>6LoWPAN；</li><li>MLE；</li><li>IPv6 &#x2F; UDP；</li><li>CoAP；</li><li>加密后的 Matter 消息。</li></ul><p>Thread Network Key 可以帮助分析 Thread 网络层，但不能因此解密 Matter CASE 业务负载。</p><p>继续阅读：</p><ul><li><a href="https://threadgroup.org/what-Is-thread/overview">Thread 官方概览</a></li><li><a href="https://www.threadgroup.org/Portals/0/documents/support/Thread%20Network%20Fundamentals_v3.pdf">Thread Network Fundamentals</a></li><li><a href="https://openthread.io/guides">OpenThread 文档</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/thread-foundations/</id>
    <link href="https://onium.top/posts/thread-foundations/"/>
    <published>2026-07-28T12:10:00.000Z</published>
    <summary>
      <![CDATA[<p>Thread 是建立在 IEEE 802.15.4 之上的低功耗 IPv6 Mesh 网络协议。它提供网络连接能力，但不规定灯、传感器或门锁应该有哪些应用 Cluster。</p>]]>
    </summary>
    <title>Thread 基础概念：IPv6 Mesh、设备角色与 Border Router</title>
    <updated>2026-07-28T13:39:02.854Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="无线协议" scheme="https://onium.top/categories/%E6%97%A0%E7%BA%BF%E5%8D%8F%E8%AE%AE/"/>
    <category term="Matter" scheme="https://onium.top/tags/matter/"/>
    <category term="Thread" scheme="https://onium.top/tags/thread/"/>
    <category term="Zigbee" scheme="https://onium.top/tags/zigbee/"/>
    <category term="协议分层" scheme="https://onium.top/tags/%E5%8D%8F%E8%AE%AE%E5%88%86%E5%B1%82/"/>
    <content>
      <![CDATA[<p>Matter 和 Zigbee 都使用 Endpoint、Cluster、Attribute、Command 等概念，但它们的网络、安全和设备生命周期不同。做迁移或 Bridge 时，可以映射业务语义，不能按名字直接替换协议结构。</p><span id="more"></span><h2 id="分层对照"><a href="#分层对照" class="headerlink" title="分层对照"></a>分层对照</h2><table><thead><tr><th>维度</th><th>Matter</th><th>Zigbee</th></tr></thead><tbody><tr><td>应用标准</td><td>Matter Data Model &#x2F; Interaction Model</td><td>ZCL 与应用 Profile &#x2F; Device Type</td></tr><tr><td>网络</td><td>IPv6</td><td>Zigbee NWK</td></tr><tr><td>传输</td><td>UDP + Matter 消息层</td><td>APS</td></tr><tr><td>低功耗 Mesh</td><td>可运行于 Thread</td><td>Zigbee 自身 Mesh</td></tr><tr><td>无线底层</td><td>Thread 时使用 IEEE 802.15.4</td><td>常见为 IEEE 802.15.4</td></tr><tr><td>信任域</td><td>Fabric</td><td>Zigbee Network &#x2F; Trust Center 模型</td></tr><tr><td>日常单播安全</td><td>CASE</td><td>NWK Security，可叠加 APS Link Key</td></tr><tr><td>初次配置</td><td>PASE + 网络配置 + NOC</td><td>BDB commissioning + Key 流程</td></tr></tbody></table><p>共享 IEEE 802.15.4 不代表空口互通。Matter over Thread 帧不能由 Zigbee 节点直接当作 ZCL 消息处理。</p><h2 id="数据模型对照"><a href="#数据模型对照" class="headerlink" title="数据模型对照"></a>数据模型对照</h2><table><thead><tr><th>Matter</th><th>Zigbee</th><th>是否一一对应</th></tr></thead><tbody><tr><td>Node</td><td>Zigbee Node</td><td>仅概念相近</td></tr><tr><td>Endpoint</td><td>Endpoint</td><td>结构相近，规则不同</td></tr><tr><td>Device Type</td><td>Device ID &#x2F; Device Type</td><td>语义需逐项映射</td></tr><tr><td>Cluster</td><td>Cluster</td><td>名称可能相近，ID 和定义不同</td></tr><tr><td>Attribute</td><td>Attribute</td><td>概念相近，类型与语义可能不同</td></tr><tr><td>Command</td><td>Command</td><td>需映射方向、状态和载荷</td></tr><tr><td>Event</td><td>Reporting 或专用 Command</td><td>通常没有统一一一对应</td></tr><tr><td>FeatureMap</td><td>Optional 能力与 PICS</td><td>表达方式不同</td></tr></tbody></table><p>迁移时应从业务语义出发，而不是复制数值 ID。</p><h2 id="入网与-commissioning-对照"><a href="#入网与-commissioning-对照" class="headerlink" title="入网与 commissioning 对照"></a>入网与 commissioning 对照</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Matter:</span><br><span class="line">发现 -&gt; PASE -&gt; Attestation -&gt; 网络配置 -&gt; NOC -&gt; CASE -&gt; 完成</span><br><span class="line"></span><br><span class="line">Zigbee:</span><br><span class="line">扫描 -&gt; 关联 -&gt; Network Key -&gt; 安全通信 -&gt; TCLK/BDB -&gt; 应用发现</span><br></pre></td></tr></table></figure><p>两边都有“发现、鉴权、配网、建立长期身份”的目标，但协议消息、凭据和成功锚点完全不同。</p><h2 id="安全概念不要硬映射"><a href="#安全概念不要硬映射" class="headerlink" title="安全概念不要硬映射"></a>安全概念不要硬映射</h2><ul><li>Matter Fabric 不是 Zigbee PAN；</li><li>Matter NOC 不是 Zigbee Network Key；</li><li>Matter PASE setup passcode 不是 Zigbee install code；</li><li>Matter CASE 不是 Zigbee APS 加密；</li><li>Matter Device Attestation 不等于 Zigbee Trust Center 准入。</li></ul><p>它们只能在安全目的层面类比，不能在实现或日志中互换。</p><h2 id="Thread-与-Zigbee-的位置"><a href="#Thread-与-Zigbee-的位置" class="headerlink" title="Thread 与 Zigbee 的位置"></a>Thread 与 Zigbee 的位置</h2><p>Matter 可以运行在 Thread、Wi-Fi 或 Ethernet 上。Thread 提供 IPv6 Mesh，不规定应用 Cluster。</p><p>Zigbee 从网络到应用数据模型形成另一条完整栈。二者都可能占用 2.4 GHz IEEE 802.15.4 信道，因此还要考虑射频共存，但不能因为底层相同就混用密钥或抓包过滤器。</p><h2 id="Bridge-真正映射什么"><a href="#Bridge-真正映射什么" class="headerlink" title="Bridge 真正映射什么"></a>Bridge 真正映射什么</h2><p>Zigbee-to-Matter Bridge 通常需要维护：</p><ol><li>Zigbee 设备身份与 Matter Bridged Node Endpoint；</li><li>Device Type 与 Cluster 语义映射；</li><li>Zigbee Attribute &#x2F; Command 与 Matter Attribute &#x2F; Command &#x2F; Event；</li><li>单位、范围、无效值和质量状态；</li><li>在线状态、删除、重入网和 Endpoint 生命周期；</li><li>Zigbee reporting 与 Matter subscription；</li><li>Zigbee 网络安全边界与 Matter Fabric 访问控制。</li></ol><p>Bridge 不是透明转发器。它终止两边协议，并在应用层重建语义。</p><h2 id="一个映射检查表"><a href="#一个映射检查表" class="headerlink" title="一个映射检查表"></a>一个映射检查表</h2><p>对每项功能记录：</p><table><thead><tr><th>字段</th><th>内容</th></tr></thead><tbody><tr><td>用户语义</td><td>用户看到的状态或动作</td></tr><tr><td>Zigbee 来源</td><td>Endpoint、Cluster、Attribute&#x2F;Command</td></tr><tr><td>Matter 目标</td><td>Endpoint、Device Type、Cluster、Feature</td></tr><tr><td>数据转换</td><td>类型、单位、范围、特殊值</td></tr><tr><td>方向</td><td>读、写、命令、上报、事件</td></tr><tr><td>生命周期</td><td>加入、离线、删除、恢复</td></tr><tr><td>错误映射</td><td>Zigbee 状态如何转换</td></tr><tr><td>证据</td><td>抓包、日志、互操作与认证测试</td></tr></tbody></table><p>官方基础资料可参考 <a href="https://project-chip.github.io/connectedhomeip-doc/">Matter SDK 文档</a>、<a href="https://csa-iot.org/all-solutions/zigbee/">Zigbee 官方介绍</a>和 <a href="https://threadgroup.org/what-Is-thread/overview">Thread 官方概览</a>。</p>]]>
    </content>
    <id>https://onium.top/posts/matter-zigbee-concept-mapping/</id>
    <link href="https://onium.top/posts/matter-zigbee-concept-mapping/"/>
    <published>2026-07-28T12:00:00.000Z</published>
    <summary>
      <![CDATA[<p>Matter 和 Zigbee 都使用 Endpoint、Cluster、Attribute、Command 等概念，但它们的网络、安全和设备生命周期不同。做迁移或 Bridge 时，可以映射业务语义，不能按名字直接替换协议结构。</p>]]>
    </summary>
    <title>Matter 与 Zigbee 关系映射：相似名词不等于相同协议</title>
    <updated>2026-07-28T13:39:02.854Z</updated>
  </entry>
  <entry>
    <author>
      <name>Oniums</name>
    </author>
    <category term="认证实践" scheme="https://onium.top/categories/%E8%AE%A4%E8%AF%81%E5%AE%9E%E8%B7%B5/"/>
    <category term="Matter" scheme="https://onium.top/tags/matter/"/>
    <category term="Test Harness" scheme="https://onium.top/tags/test-harness/"/>
    <category term="PICS" scheme="https://onium.top/tags/pics/"/>
    <category term="环境搭建" scheme="https://onium.top/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    <content>
      <![CDATA[<p>Matter 认证环境不是一台电脑加一个 <code>chip-tool</code>。稳定的预认证环境需要把 Test Harness、Device Under Test、参考节点、网络基础设施、PICS 和版本证据作为一个整体管理。</p><span id="more"></span><h2 id="先冻结版本组合"><a href="#先冻结版本组合" class="headerlink" title="先冻结版本组合"></a>先冻结版本组合</h2><p>在安装前确认：</p><ul><li>目标 Matter Specification 版本；</li><li>对应 Test Plan、PICS&#x2F;PIXIT 和 CCB；</li><li>Test Harness 发布版本或镜像；</li><li>Test Harness 使用的 Matter SDK commit；</li><li>DUT 的网络传输：Thread、Wi-Fi 或 Ethernet；</li><li>认证路径：完整产品、平台或派生产品；</li><li>实验室接受的设备与辅助硬件。</li></ul><p>Test Harness、SDK、测试脚本和 PICS 之间存在版本配套关系。只更新其中一项可能制造环境假失败。</p><h2 id="推荐架构"><a href="#推荐架构" class="headerlink" title="推荐架构"></a>推荐架构</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">浏览器工作站</span><br><span class="line">      │</span><br><span class="line">Matter Test Harness 主机</span><br><span class="line">  ├── Web / Backend / Database</span><br><span class="line">  ├── 参考 Commissioner 或 Accessory</span><br><span class="line">  ├── 测试脚本与日志</span><br><span class="line">  └── OTBR（Thread DUT 时）</span><br><span class="line">          │</span><br><span class="line">        RCP</span><br><span class="line">          │ IEEE 802.15.4</span><br><span class="line">         DUT</span><br></pre></td></tr></table></figure><p>Wi-Fi &#x2F; Ethernet DUT 还需要稳定、可控且支持 IPv6 与组播的局域网。</p><h2 id="硬件准备"><a href="#硬件准备" class="headerlink" title="硬件准备"></a>硬件准备</h2><p>当前官方 Test Harness 用户指南以 Raspberry Pi 4 或 5、至少 8 GB RAM 和至少 64 GB 存储作为完整环境的基础示例。Thread DUT 还需要受支持固件的 RCP。</p><p>实际送测前以对应 Test Harness 版本的用户指南为准，不要把这组规格当作永久不变的认证要求。</p><p>建议额外准备：</p><ul><li>两台或以上独立 DUT；</li><li>串口日志采集器；</li><li>可控电源与重启方式；</li><li>独立抓包器；</li><li>有线管理网络；</li><li>时间同步；</li><li>足够保存镜像、数据库和原始日志的空间。</li></ul><h2 id="网络准备"><a href="#网络准备" class="headerlink" title="网络准备"></a>网络准备</h2><p>Matter 对本地网络提出的典型基础要求：</p><ul><li>IPv6 可用；</li><li>mDNS &#x2F; DNS-SD 组播不被错误阻断；</li><li>主机路由和接口选择明确；</li><li>防火墙不拦截测试流量；</li><li>Wi-Fi SSID 与 Thread Dataset 独立保存；</li><li>测试网与办公网、生产网隔离。</li></ul><p>不要在公开配置文件中提交 Wi-Fi 密码、Thread Dataset、setup passcode 或证书私钥。</p><h2 id="安装原则"><a href="#安装原则" class="headerlink" title="安装原则"></a>安装原则</h2><ol><li>从 <a href="https://github.com/project-chip/certification-tool">官方 certification-tool 仓库</a>选择目标 release 或 commit；</li><li>完整阅读该版本的 <code>Matter_TH_User_Guide</code>；</li><li>使用文档指定的系统镜像、容器和 SDK 配套；</li><li>记录每个镜像、仓库和 RCP 固件的版本；</li><li>先用官方参考节点完成环境冒烟测试；</li><li>再接入自己的 DUT。</li></ol><p>不要把 <code>main</code> 分支当天状态当作认证基线，也不要在问题出现后无记录地升级整个环境。</p><h2 id="DUT-准备"><a href="#DUT-准备" class="headerlink" title="DUT 准备"></a>DUT 准备</h2><p>DUT 至少应支持：</p><ul><li>稳定进入和退出 commissioning 模式；</li><li>可靠恢复出厂；</li><li>可识别的固件、硬件版本；</li><li>测试要求的自动化触发或人工操作；</li><li>持续串口日志；</li><li>正确的 Device Attestation Credentials；</li><li>与 PICS 一致的 Endpoint、Device Type 和 Cluster。</li></ul><p>开发测试凭据与认证&#x2F;量产凭据必须隔离。正式认证是否要求独立 provisioned DUT 及具体样机数量，应按当前计划和实验室要求执行。</p><h2 id="PICS-驱动测试"><a href="#PICS-驱动测试" class="headerlink" title="PICS 驱动测试"></a>PICS 驱动测试</h2><p>Test Harness 根据 PICS 选择适用用例。推荐流程：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">审查 Data Model</span><br><span class="line">  -&gt; 填写 PICS / PIXIT</span><br><span class="line">  -&gt; PICS Tool 校验</span><br><span class="line">  -&gt; 导入 Test Harness</span><br><span class="line">  -&gt; 检查自动选择的用例</span><br><span class="line">  -&gt; 运行并审查原始日志</span><br></pre></td></tr></table></figure><p>用例没被选中不自动表示“不适用”，也可能是 PICS 填错。</p><h2 id="环境验收"><a href="#环境验收" class="headerlink" title="环境验收"></a>环境验收</h2><p>在测试产品功能前，先证明环境：</p><ul><li>Web UI、Backend 与数据库健康；</li><li>参考 Commissioner &#x2F; Accessory 可运行；</li><li>BLE adapter 可发现参考 DUT；</li><li>Thread 时 OTBR 与 RCP 正常；</li><li>Wi-Fi &#x2F; Ethernet 时 IPv6 和 mDNS 正常；</li><li>测试主机时间一致；</li><li>日志、报告和备份可导出；</li><li>恢复出厂后可重复 commissioning。</li></ul><h2 id="证据与故障隔离"><a href="#证据与故障隔离" class="headerlink" title="证据与故障隔离"></a>证据与故障隔离</h2><p>每次运行保存：</p><ul><li>Test Harness、SDK、镜像和脚本版本；</li><li>PICS &#x2F; PIXIT；</li><li>DUT 固件和构建标识；</li><li>测试项目配置的脱敏副本；</li><li>Test Harness、DUT、OTBR 和抓包日志；</li><li>用例结果与人工操作记录。</li></ul><p>先用参考节点区分“环境坏了”还是“DUT 有问题”，再进入产品代码分析。</p><p>官方入口：</p><ul><li><a href="https://github.com/project-chip/certification-tool/blob/main/docs/Matter_TH_User_Guide/Matter_TH_User_Guide.adoc">Matter Test Harness User Guide</a></li><li><a href="https://csa-iot.org/certification/tools/">CSA 认证工具</a></li><li><a href="https://project-chip.github.io/connectedhomeip-doc/testing/index.html">Matter SDK 测试文档</a></li></ul>]]>
    </content>
    <id>https://onium.top/posts/matter-certification-test-environment/</id>
    <link href="https://onium.top/posts/matter-certification-test-environment/"/>
    <published>2026-07-28T11:50:00.000Z</published>
    <summary>
      <![CDATA[<p>Matter 认证环境不是一台电脑加一个 <code>chip-tool</code>。稳定的预认证环境需要把 Test Harness、Device Under Test、参考节点、网络基础设施、PICS 和版本证据作为一个整体管理。</p>]]>
    </summary>
    <title>Matter 认证环境搭建：Test Harness、DUT 与网络基础设施</title>
    <updated>2026-07-28T13:39:02.854Z</updated>
  </entry>
</feed>
