GATT Characteristic 是 GATT 中表示一个具体状态值、测量值或控制入口的数据项,由 characteristic declaration、characteristic value 和可选 GATT Descriptor 组成。
核心问题
Service 只说明“这是电池服务”或“这是设备信息服务”,还需要更细的单个数据项来表达“电量是多少”“固件版本是什么”“写入哪个字段能触发动作”。Characteristic 就是这些可访问数据项的单位。
核心机制
Characteristic declaration 是一个 attribute,类型为 0x2803,其 value 包含三部分:
Characteristic Declaration Value =
properties # 1 octet bit field
value_handle # 2 octets
characteristic_uuid示例:
0x0002 type=0x2803 value={properties=read|notify, value_handle=0x0003, uuid=0x2A19}
0x0003 type=0x2A19 value=85
0x0004 type=0x2902 value=0x0000这里真正的电量值在 0x0003,不是 declaration 本身。properties 告诉客户端可以对 value 执行哪些 GATT 过程,例如 read、write、notify、indicate。value_handle 告诉客户端读写哪个 handle。characteristic_uuid 告诉客户端这个值是什么类型。
工程用途
- 表示设备状态:电池电量、温度、门锁状态。
- 表示控制入口:写入配置、命令、阈值或模式。
- 表示事件流:通过 notification/indication 推送变化。
- 承载自定义小协议:一个 write characteristic + 一个 notify characteristic 是常见设计。
边界与常见坑
- 不要读写 declaration handle 当成 value handle:声明 handle 只描述 characteristic,真正数据在 value handle。
- properties 不是 permissions:properties 声明支持哪些过程,permissions 决定当前连接是否满足安全条件。
- value 字节结构要另查规范:UUID 只能告诉类型,具体位域、单位、端序和缩放常由 service spec 或厂商协议定义。
- notify 需要 CCCD:仅 characteristic properties 支持 notify 不够,client 通常还要写 descriptor 订阅。
- 一个 UUID 可以在多个 service 中出现:解释 characteristic 时要结合所属 service。