消息模型与编解码
本篇讲清楚一条消息从代码里的字典到设备端的二进制、再到你收到的字典,中间都经过了什么。
Topic 命名规则
所有业务 Topic 采用三段式命名,目前的前缀都是 lixel/application/:
lixel/<domain>/<type>/<name>
domain:业务域,目前所有业务 Topic 都使用application。type:消息方向。request:客户端 → 设备(请求)response:设备 → 客户端(对请求的应答)report:设备 → 客户端(主动上报)
name:具体功能,如device_info、modeling、lio_pose。
例如查询设备信息,请求发往 lixel/application/request/device_info,响应来自 lixel/application/response/device_info。
消息负载
除心跳外,所有消息负载都是 Protobuf 二进制,proto 包名为 openapi.aiot_msgs。OpenAPI 公开的接口中,只有心跳采用 JSON 文本,便于在不解析 Protobuf 的情况下发现设备、读取协议版本。
编译 Proto
使用项目自带脚本,把 proto 定义编译为 Python 模块:
python src/generate_proto.py
注:编译使用当前环境的
grpc_tools.protoc,确保生成代码与运行时的 protobuf 版本一致。运行时建议设置PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python,避免不同环境下 C 扩展不兼容。
JSON 与 Protobuf 互转
项目客户端封装提供 ProtoCodec,基于 google.protobuf.json_format,在字典 / JSON 与 Protobuf 二进制之间转换:
from example.core import ProtoCodec
codec = ProtoCodec()
# 编码:dict → Protobuf 二进制
data = codec.encode("DeviceControlRequest", {"action": "AC_SYSTEM_REBOOT"})
# 解码:Protobuf 二进制 → dict
result = codec.decode("DeviceControlResponse", data)
# 生成默认模板(含所有字段)
template = codec.default_json("ModelingRequest")
要点:
- 枚举字段可以直接用字符串名(如
"AC_START"),也可以用整数值。 bytes字段在字典中表现为 base64 字符串。- 字段名保持 proto 定义中的 snake_case 写法。
消息方向标记
接口清单中用三种标记表示消息方向,后续章节沿用:
| 标记 | 含义 | Topic 段 |
|---|---|---|
| REQ | 请求(客户端 → 设备) | request |
| RSP | 响应(设备 → 客户端) | response |
| RPT | 上报(设备 → 客户端) | report |
错误承载
请求-响应类消息在响应里用 Error error = 15 字段承载结果:
message Error {
uint32 code = 1; // 错误码
string desc = 2; // 描述
}
错误码的分类与含义见 错误码。