MQTT Topic Design 文档(公司级规范)
📘 MQTT Topic Design 文档模板(公司级规范)
版本:v1.0
适用范围:本公司所有 IoT、智能设备、会议室系统、场景控制等 MQTT 通讯项目
作者:xxx
日期:yyyy-MM-dd
1. 设计目标
本规范旨在统一 MQTT Topic 的命名规则,确保:
- 拓扑结构清晰(公司 → 房间 → 设备 → 场景)
- 易扩展(设备可独立存在,也可属于房间)
- 可维护(业务方、开发、运维均可理解)
- 避免 Topic 冲突
- 兼容未来分组、权限、灰度、区域化部署
2. Topic 基础原则
2.1 使用“/”作为层级分隔符
companyId/roomId/deviceId/resource2.2 使用小写、数字与短横线(-)
my-company
room-001
device-ac-012.3 不使用中文、不使用空格
2.4 保持同层级字段含义一致
3. Topic 总体结构
3.1 设备在房间中的标准 Topic(推荐)
{companyId}/{roomId}/{deviceId}/{messageType}示例:
abc-corp/room-302/light-01/state
abc-corp/room-302/ac-01/control3.2 设备独立存在的 Topic(无 roomId)
{companyId}/_global/{deviceId}/{messageType}示例:
abc-corp/_global/sensor-01/state
abc-corp/_global/robot-arm-01/control
_global为保留关键字,用于表示不属于任何房间。
4. Topic 字段定义
| 字段 | 含义 | 示例 | 说明 |
|---|---|---|---|
| companyId | 公司唯一标识 | abc-corp | 必填 |
| roomId | 房间/会议室唯一 ID | room-101 | 可选(设备独立存在时为空) |
| deviceId | 设备唯一标识 | light-01 | 必填 |
| messageType | 消息类型/资源 | state/control/event/config | 必填 |
5. messageType 规范
5.1 设备状态上报
state示例:
abc-corp/room-101/light-01/state内容:
{
"power": "on",
"brightness": 70
}5.2 控制下发
control示例:
abc-corp/room-101/light-01/control内容:
{
"power": "off"
}5.3 事件(设备主动触发)
event示例:
abc-corp/room-101/ac-02/event内容:
{
"temperature_high": true
}5.4 配置同步
config5.5 OTA 升级
ota/update
ota/report6. 场景 Topic 设计
场景是多个设备的逻辑组合,因此采用:
{companyId}/{roomId}/scene/{sceneId}/{messageType}示例:
abc-corp/room-101/scene/meeting-on/control
abc-corp/room-101/scene/movie-night/state场景触发后可能控制多个设备:
{
"deviceActions": [
{ "deviceId": "light-01", "power": "off" },
{ "deviceId": "curtain-01", "position": 90 },
{ "deviceId": "projector-01", "power": "on" }
]
}✔ 场景消息由服务端(云端)接收
订阅:
company/room/scene/{sceneId}/command
当云端收到场景消息后会做:
① 查 sceneId 对应设备列表
例如 sceneA → [dev01, dev02, dev05]
② 服务端依次发布到设备的 topic
mycorp/room101/dev01/command
mycorp/room101/dev02/command
mycorp/room101/dev05/command设备收到自己的 command 就执行动作。
⭐ 场景控制的逻辑:由服务端负责 Fan-out(广播)
流程图(简洁版)
手机/前端 → 发布 → 场景Topic
↓
Spring Boot(场景控制服务)
↓
查场景-设备映射(Redis/DB)
↓↓↓
发布到多个设备Topic(自动 fan-out)
dev01 → 执行动作
dev02 → 执行动作
dev05 → 执行动作设备层 无需知道场景逻辑。
📌 三、设备应该如何订阅 Topic?
设备永远只关注自己的命令:
company/{roomId}/device/{deviceId}/command
Examples:
mycorp/room101/dev01/command
mycorp/_global/dev99/command设备订阅规则:
| 设备类型 | 订阅 Topic |
|---|---|
| 房间内设备 | company/room/deviceId/command |
| 跨房间设备 | company/_global/deviceId/command |
设备不需要订阅:
- 场景 Topic
- 别的房间 Topic
- 广播 Topic(如果你没有设计)
- 控制场景的 Topic
🟩 四、场景 → 设备传播代码示例(Spring Boot)
MQ 接收场景命令
@MqttSubscription("${company}/+ /scene/+/command")
public void onSceneCommand(String topic, String payload) {
String sceneId = extractSceneId(topic);
// 查场景对应的设备
List<String> deviceIds = sceneService.getDevices(sceneId);
SceneCommand command = parse(payload);
for (String deviceId : deviceIds) {
String deviceTopic = TopicBuilder.create()
.company(company)
.room(room)
.device(deviceId)
.type("command")
.build();
mqttTemplate.publish(deviceTopic, command);
}
}核心点:
服务端 fan-out → 设备执行命令。
🟦 五、你可能问的扩展问题
Q1:多个 Spring Boot 服务实例会不会重复 fan-out?
不会 ✔
你使用 Shared Subscription:
$share/iot-workers/company/+/scene/+/command
EMQX 会自动做负载均衡,只让一个实例处理。
Q2:如果设备也想收到 “全局场景” 呢?
你可以设计广播 topic:
company/_global/scene/{sceneId}/command
服务端处理后 fan-out 到:
company/_global/{deviceId}/command
依然设备只订阅自己的 command topic。
Q3:场景是否可以动态增删设备?
完全可以,需要在数据库或 Redis 维护:
sceneA → dev01, dev02
sceneB → dev02, dev03, dev08然后服务端动态 fan-out。
📘 六、最终结论(非常重要)
| 角色 | 订阅什么? | 发布什么? |
|---|---|---|
| 设备 | 只订阅设备自己的 topic | 回状态、告警等 |
| 场景控制服务 | 订阅 scene/{sceneId}/command | 转发至多个设备 topic |
设备永远不直接订阅场景 Topic
场景控制=服务端实现的 fan-out
7. 订阅策略(服务端)
服务端常用的订阅方式:
7.1 全部设备
+/+/+/state
+/+/+/event7.2 某公司所有设备
abc-corp/+/+/state
abc-corp/_global/+/state7.3 某房间所有设备
abc-corp/room-101/+/state7.4 某设备所有消息
abc-corp/room-101/light-01/#8. 设备端订阅策略
8.1 接收自己的控制指令
{companyId}/{roomId}/{deviceId}/control8.2 接收场景控制指令
{companyId}/{roomId}/scene/+/control9. 保留字段规范(保留,不被业务占用)
以下 topic 必须保留,业务不得使用:
_global
system
internal
broadcast10. Topic 示例集(完整)
房间内设备
| 使用场景 | Topic |
|---|---|
| 灯状态上报 | abc-corp/room-502/light-01/state |
| 灯控制 | abc-corp/room-502/light-01/control |
| 灯事件 | abc-corp/room-502/light-01/event |
设备独立存在
| 使用场景 | Topic |
|---|---|
| 传感器状态 | abc-corp/_global/sensor-001/state |
| 机器人控制 | abc-corp/_global/robot-01/control |
场景
| 场景 | Topic |
|---|---|
| 会议模式 | abc-corp/room-301/scene/meeting/control |
| 离开模式 | abc-corp/room-301/scene/leave/control |
11. FAQ(常见问题)
Q1:为什么设备独立存在需要 _global ?
为了让订阅策略统一且不与房间编号冲突。
Q2:Scene 是否可以跨房间?
不建议。跨房间建议业务系统多条指令控制。
Q3:topic 是否需要公司编码 + 公司 ID?
视你们业务规模决定。大部分公司一个 ID 即可。
12. 版本控制
| 版本 | 变更内容 | 时间 |
|---|---|---|
| v1.0 | 初版 | yyyy-MM-dd |
如果你愿意,我可以根据你公司业务特点进一步为你 定制一个适合你们的 Topic 结构图(可视化版)。
#消息队列 #MQTT