时间同步 Cluster(TimeSynchronization)
Cluster ID: 0x0038 |
所在 Endpoint: 固定在 Endpoint 0(Root Endpoint)
TimeSynchronization 负责 Matter 设备的时间管理 —— 让设备知道「现在几点」「在哪个时区」「有没有夏令时」。 很多功能依赖准确的时间:定时自动化、日志时间戳、证书有效期校验、能源统计等。 没有时间同步,这些功能要么无法工作,要么会给出错误的结果。
TimeSynchronization Cluster 定义了三个 Feature,设备根据自身能力选择支持: TZ(时区管理)支持时区列表和夏令时配置; NTPC(NTP 客户端)可主动从 NTP 服务器获取时间; NTPS(NTP 服务器)可作为时间源向其他设备提供时间。 未启用任何 Feature 的设备仅支持最基础的 SetUTCTime 手动设置时间。
命令(Commands)
TimeSynchronization Cluster 共有 5 个请求命令,其中 SetTimeZone 有对应的响应命令。 最基础的 SetUTCTime 所有设备都支持,其余命令需要设备启用对应的 Feature。 点击下方表格中的命令 ID 可跳转到对应的详细说明。
| ID | 名称 | 说明 | 所需特性 |
|---|---|---|---|
0x00 |
SetUTCTime | 设置设备的 UTC 时间 | 无 |
0x01 |
SetTrustedTimeSource | 指定可信时间源节点 | 无 |
0x02 |
SetTimeZone | 设置时区列表 | TZ |
0x04 |
SetDSTOffset | 设置夏令时偏移列表 | TZ |
0x05 |
SetDefaultNTP | 设置默认 NTP 服务器地址 | NTPC |
SetUTCTime —— 设置 UTC 时间(0x00)
直接设置设备的 UTC 时间。这是最基础的时间设置方式 —— 在配网阶段,Commissioner 通常通过此命令为设备注入当前时间。
设备收到后会同时更新 Granularity 和 TimeSource 属性。
| 参数 | 类型 | 说明 |
|---|---|---|
| UTCTime | epoch_us | UTC 时间,微秒级(自 2000-01-01T00:00:00Z 起的微秒数) |
| Granularity | GranularityEnum | 时间精度等级 —— 告知设备这个时间有多精确 |
| TimeSource | TimeSourceEnum | 时间来源 —— 告知设备这个时间从哪里获取 |
设备会根据 Granularity 参数判断时间的可靠性。
如果设备当前已有更高精度的时间源(例如已从 NTP 同步),它可能会拒绝来自低精度源的 SetUTCTime 请求。
配网阶段设备通常没有时间,此时设置一定会成功。
使用场景
最常见的使用场景是配网完成后,Commissioner 立即调用 SetUTCTime 为设备设置初始时间。
Granularity 通常传 SecondsGranularity (2) 或 MillisecondsGranularity (3),
TimeSource 传 Admin (2)(表示时间由管理者手动设置)。
SetTrustedTimeSource —— 设置可信时间源(0x01)
指定一个 Fabric 内的节点作为可信时间源。设备会周期性地从这个节点同步时间,
类似于局域网内部的「时间权威」。设置为 null 可清除可信时间源。
| 参数 | 类型 | 说明 |
|---|---|---|
| TrustedTimeSource | struct / null | 可信时间源节点信息,包含 NodeID 和 Endpoint。设为 null 清除 |
TrustedTimeSource 结构体
| 字段 | 类型 | 说明 |
|---|---|---|
| NodeID | node-id | 时间源节点的 Node ID |
| Endpoint | endpoint-no | 该节点上 TimeSynchronization Cluster 所在的 Endpoint(通常是 0) |
使用场景
在 Fabric 中,通常由 Hub(如 Apple HomePod、Google Nest Hub)充当可信时间源。 Commissioner 在配网时设置 TrustedTimeSource 指向 Hub 的 Node ID, 之后设备就会自动从 Hub 同步时间,无需外部 NTP 服务器。 这对于没有直接互联网访问的 Thread 设备尤其重要。
SetTimeZone —— 设置时区(0x02)
设置设备的时区列表。可以包含多个时区条目,每个条目有生效时间(validAt),
用于支持历史或未来的时区变更。设备处理成功后返回 SetTimeZoneResponse,
告知 Commissioner 是否需要继续设置夏令时偏移。
| 参数 | 类型 | 说明 |
|---|---|---|
| TimeZone | list<TimeZoneStruct> | 时区列表(最多 TimeZoneListMaxSize 个条目) |
TimeZoneStruct 结构体
| 字段 | 类型 | 说明 |
|---|---|---|
| Offset | int32 | 相对 UTC 的偏移量,单位秒。例如 UTC+8 = 28800,UTC-5 = -18000 |
| ValidAt | epoch_us | 此条目的生效时间(微秒级 epoch)。第一个条目的 ValidAt 必须为 0 |
| Name | string(可选) | IANA 时区名称(如 "Asia/Shanghai"),用于显示和夏令时数据库查询 |
SetTimeZoneResponse 响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
| DSTOffsetRequired | bool | true 表示设备需要 Commissioner 接着调用 SetDSTOffset |
如果设备内置了 IANA 时区数据库(TimeZoneDatabase = Full),
设备可以自己推算夏令时规则,此时响应 DSTOffsetRequired = false。
如果设备没有时区数据库(TimeZoneDatabase = None),
则返回 true,Commissioner 必须手动下发夏令时偏移。
使用场景
用户搬家到新时区,或设备首次配网时需要设置时区。 对于中国用户,通常只需一条记录:Offset = 28800(UTC+8),ValidAt = 0,Name = "Asia/Shanghai"。 中国没有夏令时,所以 DSTOffset 可以设为偏移量 0 的单条记录。
SetDSTOffset —— 设置夏令时偏移(0x04)
设置夏令时(DST)偏移列表。每个条目定义一段时间范围内的额外偏移量。 设备根据当前时间匹配对应的条目,将偏移量叠加到时区偏移上,得出本地时间。
| 参数 | 类型 | 说明 |
|---|---|---|
| DSTOffset | list<DSTOffsetStruct> | 夏令时偏移列表(最多 DSTOffsetListMaxSize 个条目) |
DSTOffsetStruct 结构体
| 字段 | 类型 | 说明 |
|---|---|---|
| Offset | int32 | 夏令时额外偏移量,单位秒。例如美国夏令时 = 3600(+1 小时),无夏令时 = 0 |
| ValidStarting | epoch_us | 此条目的生效起始时间(微秒级 epoch) |
| ValidUntil | epoch_us / null | 此条目的失效时间。最后一条的 ValidUntil 必须为 null(表示一直有效直到被新列表替换) |
LocalTime = UTCTime + TimeZone.Offset + DSTOffset.Offset
例如:UTC 时间 12:00,时区 UTC+8(28800 秒),夏令时 +1h(3600 秒)→ 本地时间 21:00。
对于不使用夏令时的地区(如中国),DSTOffset 列表只需一条 Offset = 0 的记录。
使用场景
美国东部时区(UTC-5)的设备需要在每年 3 月第二个周日进入夏令时(+1h),
11 月第一个周日退出。Commissioner 可以下发两条 DSTOffset 记录来覆盖当前年份的切换。
当列表中最后一条的 ValidUntil 到期后,设备会触发 DSTTableEmpty 事件,
提醒 Commissioner 需要更新夏令时表。
SetDefaultNTP —— 设置默认 NTP 服务器(0x05)
设置设备用于时间同步的默认 NTP 服务器地址。需要设备启用 NTPC(NTP 客户端)特性。
设为 null 可清除默认 NTP 服务器。
| 参数 | 类型 | 说明 |
|---|---|---|
| DefaultNTP | string / null | NTP 服务器地址(域名或 IPv6 地址)。设为 null 清除 |
如果传入的是域名(如 "pool.ntp.org"),设备需要具备 DNS 解析能力
(检查 SupportsDNSResolve 属性)。
不支持 DNS 的设备只能接受 IPv6 地址形式的 NTP 服务器。
使用场景
配网完成后,Commissioner 可以为支持 NTPC 的设备配置 NTP 服务器。
设备随后会自动通过 NTP 协议同步时间,不再依赖 Commissioner 手动设置。
常用的公共 NTP 服务器:pool.ntp.org、time.google.com、ntp.aliyun.com。
属性详解
TimeSynchronization Cluster 共有 13 个应用属性。点击下方汇总表中的属性 ID 可跳转到对应的详细说明。
| ID | 名称 | 类型 | 分组 | 说明 |
|---|---|---|---|---|
0x0000 |
UTCTime | epoch_us / null | 时间状态 | 当前 UTC 时间(微秒级) |
0x0001 |
Granularity | GranularityEnum | 时间状态 | 当前时间的精度等级 |
0x0002 |
TimeSource | TimeSourceEnum | 时间状态 | 当前时间的来源 |
0x0003 |
TrustedTimeSource | struct / null | 时间源配置 | Fabric 内可信时间源节点 |
0x0004 |
DefaultNTP | string / null | 时间源配置 | 默认 NTP 服务器地址 |
0x0005 |
TimeZone | list<TimeZoneStruct> | 时区与夏令时 | 时区配置列表 |
0x0006 |
DSTOffset | list<DSTOffsetStruct> | 时区与夏令时 | 夏令时偏移列表 |
0x0007 |
LocalTime | epoch_us / null | 时区与夏令时 | 当前本地时间(已含时区 + 夏令时偏移) |
0x0008 |
TimeZoneDatabase | TimeZoneDatabaseEnum | 能力与限制 | 设备的时区数据库类型 |
0x0009 |
NTPServerAvailable | bool | 能力与限制 | 设备是否可用作 NTP 服务器 |
0x000A |
TimeZoneListMaxSize | uint8 | 能力与限制 | 时区列表最大条目数 |
0x000B |
DSTOffsetListMaxSize | uint8 | 能力与限制 | 夏令时偏移列表最大条目数 |
0x000C |
SupportsDNSResolve | bool | 能力与限制 | 是否支持 DNS 域名解析 |
时间状态(0x0000 ~ 0x0002)
描述设备当前的时间值以及时间的精度和来源。
| ID | 名称 | 类型 | 说明 |
|---|---|---|---|
0x0000 |
UTCTime UTC 时间 |
epoch_us / null |
设备当前的 UTC 时间,微秒级精度(自 2000-01-01T00:00:00Z 起)。
null 表示设备尚未获得有效时间 —— 这是刚上电、未经时间同步的设备的默认状态
|
0x0001 |
Granularity 时间精度 |
GranularityEnum |
当前时间的精度等级。NoTimeGranularity (0) 表示设备没有可信时间。
精度越高,说明时间来源越可靠(见下方枚举定义)
|
0x0002 |
TimeSource 时间来源 |
TimeSourceEnum | 当前时间是从哪里获取的 —— NTP、管理员手动设置、GNSS、还是其他 Matter 节点等。 用于判断时间的可信程度(见下方枚举定义) |
Matter 的时间 epoch 基准是 2000-01-01T00:00:00Z,不是 Unix 的 1970 年。
转换公式:Matter epoch_us = (Unix timestamp - 946684800) * 1000000。
读取 UTCTime 后需要注意转换。
时间源配置(0x0003, 0x0004)
描述设备的时间同步源 —— 从哪里获取精确时间。
| ID | 名称 | 类型 | 说明 |
|---|---|---|---|
0x0003 |
TrustedTimeSource 可信时间源 |
struct / null |
Fabric 内指定的可信时间源节点。包含 FabricIndex、NodeID 和 Endpoint 三个字段。
null 表示未配置。通过 SetTrustedTimeSource 命令设置
|
0x0004 |
DefaultNTP 默认 NTP 服务器 |
string / null |
设备使用的默认 NTP 服务器地址(域名或 IPv6 地址)。
null 表示未配置。通过 SetDefaultNTP 命令设置。
需要 NTPC 特性
|
设备获取时间的优先级通常是:NTP 服务器 > 可信时间源节点 > 管理员手动设置。 如果设备支持 NTPC 且配置了 DefaultNTP,它会自动通过 NTP 同步,精度最高。 对于不能直接访问互联网的 Thread 设备,TrustedTimeSource 是唯一的自动同步途径。
时区与夏令时(0x0005 ~ 0x0007)
管理时区配置、夏令时偏移和本地时间计算。需要设备启用 TZ 特性。
| ID | 名称 | 类型 | 说明 |
|---|---|---|---|
0x0005 |
TimeZone 时区列表 |
list<TimeZoneStruct> | 当前生效的时区配置列表。每条包含 Offset(秒)、ValidAt(生效时间)、Name(IANA 时区名)。 通过 SetTimeZone 命令设置。需要 TZ 特性 |
0x0006 |
DSTOffset 夏令时偏移列表 |
list<DSTOffsetStruct> | 当前生效的夏令时偏移列表。每条包含 Offset(秒)、ValidStarting、ValidUntil。 通过 SetDSTOffset 命令设置。需要 TZ 特性 |
0x0007 |
LocalTime 本地时间 |
epoch_us / null |
设备计算得出的本地时间 = UTCTime + TimeZone.Offset + DSTOffset.Offset。
null 表示缺少 UTC 时间或时区配置,无法计算。只读属性。需要 TZ 特性
|
能力与限制(0x0008 ~ 0x000C)
描述设备在时间同步方面的能力上限和硬件特性。这些属性大部分是只读的,由设备固件决定。
| ID | 名称 | 类型 | 说明 |
|---|---|---|---|
0x0008 |
TimeZoneDatabase 时区数据库 |
TimeZoneDatabaseEnum |
设备内置的时区数据库类型。
Full (0) = 完整 IANA 数据库,可自动推算夏令时;
Partial (1) = 部分数据库;
None (2) = 无数据库,完全依赖 Commissioner 手动设置。需要 TZ 特性
|
0x0009 |
NTPServerAvailable NTP 服务器可用 |
bool |
设备自身是否可作为 NTP 服务器向其他节点提供时间。
true 表示其他设备可以将此设备设为 TrustedTimeSource。
需要 NTPS 特性
|
0x000A |
TimeZoneListMaxSize 时区列表上限 |
uint8 | TimeZone 列表允许的最大条目数。最小为 1,最大为 2。 SetTimeZone 的列表长度不能超过此值。需要 TZ 特性 |
0x000B |
DSTOffsetListMaxSize 夏令时列表上限 |
uint8 | DSTOffset 列表允许的最大条目数。 SetDSTOffset 的列表长度不能超过此值。需要 TZ 特性 |
0x000C |
SupportsDNSResolve 支持 DNS 解析 |
bool |
设备是否支持将域名解析为 IP 地址。
如果为 false,SetDefaultNTP 只能接受 IPv6 地址,不能传域名。
需要 NTPC 特性
|
Feature 位图
TimeSynchronization Cluster 通过 FeatureMap(0xFFFC)声明设备支持哪些时间同步能力:
基础设备(如低功耗传感器):无 Feature,仅支持 SetUTCTime 手动设置;
普通设备(如灯、插座):TZ,支持时区和夏令时配置;
联网设备(如 Wi-Fi 灯):TZ + NTPC,可自动从 NTP 同步;
Hub 设备(如边界路由器):TZ + NTPC + NTPS,不仅自己同步,还能为其他设备提供时间。
枚举定义
GranularityEnum
描述设备当前时间的精度等级。精度越高,表示设备的时间源越可靠。
TimeSourceEnum
标识设备当前时间的获取来源。数值越高通常意味着更可靠的时间源。NTS 后缀表示使用了网络时间安全(Network Time Security)认证。
TimeZoneDatabaseEnum
描述设备内置的时区数据库能力,决定设备能否自行推算夏令时规则。
事件(Events)
TimeSynchronization Cluster 定义了 5 个事件,用于通知 Commissioner 或自动化系统时间状态的变化。
| 事件名称 | 严重级别 | 所需特性 | 说明 |
|---|---|---|---|
| DSTTableEmpty | Info | TZ | 夏令时表已耗尽 —— 所有 DSTOffset 条目都已过期,设备无法继续正确计算本地时间。Commissioner 需要下发新的 DSTOffset 列表 |
| DSTStatus | Info | TZ | 夏令时状态变更 —— 设备进入或退出夏令时。包含一个 DSTOffsetActive 布尔字段,true = 夏令时生效中 |
| TimeZoneStatus | Info | TZ | 时区切换 —— 时区列表中的下一条生效了(ValidAt 到达)。包含新的 Offset 和 Name 字段 |
| TimeFailure | Info | 无 | 时间同步失败 —— 设备无法从任何时间源获取或验证时间。可能是 NTP 不可达、可信时间源离线等原因 |
| MissingTrustedTimeSource | Info | 无 | 缺少可信时间源 —— 设备需要时间同步但没有配置 TrustedTimeSource,也没有可用的 NTP。提醒 Commissioner 配置时间源 |
建议 Commissioner 订阅 DSTTableEmpty 和 TimeFailure 事件。 前者在夏令时表过期时触发,如果不及时更新,设备的本地时间会出错(影响定时自动化等功能); 后者在时间同步链路断裂时触发,可及时发现并修复问题。
示例数据
属性数据示例
以下是一个支持 TZ + NTPC 的智能灯(中国地区)的 TimeSynchronization Cluster 典型属性数据:
{
// --- 时间状态 ---
"0x0000": 1695312000000000, // UTCTime = 2023-09-21T16:00:00Z(微秒级 epoch)
"0x0001": 3, // Granularity = MillisecondsGranularity
"0x0002": 7, // TimeSource = MatterNTP
// --- 信任时间源 ---
"0x0003": { // TrustedTimeSource
"fabricIndex": 1,
"nodeID": "0x0000000000000001",
"endpoint": 0
},
"0x0004": "pool.ntp.org", // DefaultNTP
// --- 时区与夏令时 ---
"0x0005": [{ // TimeZone
"offset": 28800, // UTC+8(秒)
"validAt": 0,
"name": "Asia/Shanghai"
}],
"0x0006": [{ // DSTOffset
"offset": 0, // 无夏令时
"validStarting": 0,
"validUntil": null
}],
// --- 本地时间 ---
"0x0007": 1695340800000000, // LocalTime(已加时区偏移)
// --- 能力与限制 ---
"0x0008": 1, // TimeZoneDatabase = Full
"0x0009": false, // NTPServerAvailable = false
"0x000A": 2, // TimeZoneListMaxSize = 2
"0x000B": 2, // DSTOffsetListMaxSize = 2
"0x000C": true // SupportsDNSResolve = true
}
SetUTCTime 交互示例
Commissioner 在配网完成后为设备设置初始时间:
// Commissioner → Device:设置 UTC 时间
{
"invokeRequests": [{
"commandPath": {
"endpointId": 0,
"clusterId": "0x0038",
"commandId": "0x00" // SetUTCTime
},
"commandFields": {
"UTCTime": 1695312000000000, // 2023-09-21T16:00:00Z(微秒)
"granularity": 3, // MillisecondsGranularity
"timeSource": 2 // Admin
}
}]
}
SetTimeZone 交互示例
为设备设置中国时区(UTC+8):
// Commissioner → Device:设置时区
{
"invokeRequests": [{
"commandPath": {
"endpointId": 0,
"clusterId": "0x0038",
"commandId": "0x02" // SetTimeZone
},
"commandFields": {
"timeZone": [{
"offset": 28800, // UTC+8(秒)
"validAt": 0, // 立即生效
"name": "Asia/Shanghai" // IANA 时区名(可选)
}]
}
}]
}
// Device → Commissioner:确认时区设置
{
"DSTOffsetRequired": true // 需要跟进设置夏令时偏移
}
大多数 Matter SDK(如 connectedhomeip)在配网流程中会自动处理基础的时间设置。
App 开发者通常只需要关注时区配置(特别是用户更换地区时),以及夏令时表的定期更新。
订阅 DSTTableEmpty 事件可以在需要更新时得到通知。
常见场景
场景 1:配网时设置初始时间
- 配网完成(CommissioningComplete 成功)后,读取设备的
FeatureMap (0xFFFC)确认时间同步能力 - 发送
SetUTCTime (0x00),注入当前 UTC 时间,Granularity =SecondsGranularity (2),TimeSource =Admin (2) - 发送
SetTrustedTimeSource (0x01),指定 Fabric 中的 Hub 作为可信时间源 - 如果设备支持 NTPC,发送
SetDefaultNTP (0x05)配置 NTP 服务器 - 验证:读取
UTCTime (0x0000)确认时间已设置,Granularity (0x0001)不再是 0
设备后续会自动从 NTP 或 TrustedTimeSource 同步时间,精度会逐步提升。
场景 2:时区配置(用户搬家到新时区)
- 确认设备支持 TZ 特性(
FeatureMapBit 0 = 1) - 读取
TimeZoneListMaxSize (0x000A)确认列表容量 - 发送
SetTimeZone (0x02),传入新时区信息:- 从北京搬到纽约:Offset =
-18000(UTC-5),Name ="America/New_York"
- 从北京搬到纽约:Offset =
- 检查响应的
DSTOffsetRequired:- 如果
true:设备没有内置时区数据库,需要接着调用SetDSTOffset (0x04)手动设置美东夏令时规则 - 如果
false:设备有内置数据库,已自动推算夏令时,无需额外操作
- 如果
- 验证:读取
LocalTime (0x0007)确认本地时间已正确反映新时区
场景 3:NTP 自动同步配置
- 确认设备支持 NTPC 特性(
FeatureMapBit 1 = 1) - 检查
SupportsDNSResolve (0x000C):true:可以传域名,如"pool.ntp.org"false:只能传 IPv6 地址
- 发送
SetDefaultNTP (0x05),设置 NTP 服务器地址 - 等待一段时间后,读取
Granularity (0x0001)和TimeSource (0x0002), 确认已从 NTP 成功同步(Granularity 应提升到 MillisecondsGranularity,TimeSource 变为 NTP 相关值)
推荐的 NTP 服务器:pool.ntp.org(全球)、ntp.aliyun.com(中国)、time.google.com(全球)。
对于企业环境,可以使用内部 NTP 服务器以确保安全性。
场景 4:处理 DSTTableEmpty 事件(夏令时表过期)
- 订阅设备的
DSTTableEmpty事件 - 收到事件后,说明所有 DSTOffset 条目已过期
- 根据设备所在时区查询未来的夏令时切换时间
- 发送
SetDSTOffset (0x04),下发新的夏令时偏移列表 - 最后一条的
ValidUntil设为null,确保列表覆盖到下次更新
注意:如果不及时处理此事件,设备的 LocalTime 会因为缺少夏令时信息而出错,
影响所有依赖本地时间的自动化规则(如「每天早上 7 点开灯」实际上会提前或延后一小时)。
场景 5:Thread 设备的时间同步策略
Thread 设备通常没有直接的互联网访问能力,无法使用 NTP。它们依赖以下时间同步链路:
- 配网阶段:Commissioner 通过 SetUTCTime 注入初始时间
- 运行阶段:通过 SetTrustedTimeSource 指向 Thread 边界路由器(Border Router), 边界路由器从互联网获取 NTP 时间后转发给 Thread 设备
- 如果 TrustedTimeSource 离线,设备会触发
MissingTrustedTimeSource事件 - 时间精度会逐渐降低(Granularity 可能从 Milliseconds 退化到 Seconds 甚至 Minutes)
最佳实践:确保 Fabric 中至少有一个可靠的时间源节点(如 Hub 或边界路由器), 并在配网时为所有设备配置 TrustedTimeSource 指向它。