Skip to content

通信模型

本文档定义FDP-P2P的主题设计和消息结构体。

主题设计

命名规范

{namespace}/{username}/{action}
组成部分说明示例
namespace应用命名空间,可自定义nodesdevicesmyapp
username节点唯一标识,通常与MQTT用户名一致device-001app-user-1
action操作类型pendingackcomplete

主题列表

主题用途
{ns}/{username}/pending接收任务
{ns}/{username}/ack接收确认
{ns}/{username}/progress接收进度
{ns}/{username}/complete接收完成通知
{ns}/{username}/failed接收失败通知
{ns}/{username}/status节点状态广播

订阅与发布规则

接收消息(订阅自己的主题):

订阅 nodes/{我的username}/pending    ← 接收任务
订阅 nodes/{我的username}/ack        ← 接收确认
订阅 nodes/{我的username}/complete   ← 接收完成
订阅 nodes/{我的username}/failed     ← 接收失败

发送消息(发布到对方主题):

发布到 nodes/{对方username}/pending   → 发送任务
发布到 nodes/{对方username}/ack       → 发送确认
发布到 nodes/{对方username}/complete  → 发送完成
发布到 nodes/{对方username}/failed    → 发送失败

简化订阅

根据节点角色,可简化订阅:

  • 只接收任务的设备:仅订阅 pending
  • 只发送任务的应用:仅订阅 ackcompletefailed
  • 不需要确认的场景:可不订阅 ack

消息结构体

MessagePending(任务消息)

发送任务时使用的消息结构。

json
{
  "sender": "app-001",
  "receiver": "device-001",
  "msg_id": "550e8400-e29b-41d4-a716-446655440000",
  "action": "unlock",
  "time": 1700000000,
  "exp": 1700000060,
  "value": {"door": "front"}
}
字段类型必填说明
senderstring发送者标识,用于回复消息
receiverstring接收者标识,决定发布到哪个主题
msg_idstring消息唯一ID,建议使用UUID
actionstring操作类型,业务自定义
timeint64消息创建时间戳(秒)
expint64消息过期时间戳(秒)
valueany业务数据,格式由action决定

sender字段安全提醒

sender字段可被伪造,协议层不验证其真实性。如需验证发送者身份,请使用FDP-Security安全协议

MessageAck(确认消息)

确认任务已收到。

json
{
  "msg_id": "550e8400-e29b-41d4-a716-446655440000"
}
字段类型必填说明
msg_idstring对应的任务消息ID

MessageProgress(进度消息)

报告任务执行进度。

json
{
  "msg_id": "550e8400-e29b-41d4-a716-446655440000",
  "value": 50
}
字段类型必填说明
msg_idstring对应的任务消息ID
valueany进度信息,格式自定义

进度消息特点

  • 完全可选,不影响任务结果
  • 仅用于改善用户体验
  • 建议使用 QoS 0,丢失不影响业务
  • 格式由业务决定:百分比(0-100)、分数(1/5)等

MessageComplete(完成消息)

任务执行成功。

json
{
  "msg_id": "550e8400-e29b-41d4-a716-446655440000",
  "value": {"status": "unlocked", "battery": 85}
}
字段类型必填说明
msg_idstring对应的任务消息ID
valueany返回值,格式由业务决定

MessageFailed(失败消息)

任务执行失败。

json
{
  "msg_id": "550e8400-e29b-41d4-a716-446655440000",
  "error": "door_jammed"
}
字段类型必填说明
msg_idstring对应的任务消息ID
errorstring错误信息

MessageStatus(状态消息)

节点状态广播,使用保留消息。

json
{
  "time": 1700000000,
  "online": true,
  "battery": 85,
  "rssi": -65,
  "ip": "192.168.1.100",
  "version": "1.2.0",
  "uptime": 86400
}
字段类型必填说明
timeint64状态更新时间戳(秒)
onlinebool在线状态
batteryint电量百分比 0-100
rssiint信号强度 dBm
ipstringIP地址
versionstring软件版本
uptimeint64运行时长(秒)
dataany业务自定义数据

状态消息特点

  • 使用保留消息(Retained=true),新订阅者立即收到最新状态
  • 建议定期更新(如每分钟一次)
  • 发送空载荷可删除保留消息
  • time外所有字段均可选

数据类型说明

value字段

value字段的类型由action决定,可以是:

  • 基本类型:字符串、数字、布尔值
  • 对象:JSON对象
  • 数组:JSON数组
  • 二进制:Base64编码的字符串

时间戳

所有时间戳字段均使用:

  • 单位:秒(Unix时间戳)
  • 类型:int64

结构体定义参考

Go

go
type MessagePending struct {
    Sender   string `json:"sender"`
    Receiver string `json:"receiver"`
    MsgId    string `json:"msg_id"`
    Action   string `json:"action"`
    Time     int64  `json:"time"`
    Exp      int64  `json:"exp"`
    Value    any    `json:"value,omitempty"`
}

type MessageAck struct {
    MsgId string `json:"msg_id"`
}

type MessageProgress struct {
    MsgId string `json:"msg_id"`
    Value any    `json:"value"`
}

type MessageComplete struct {
    MsgId string `json:"msg_id"`
    Value any    `json:"value,omitempty"`
}

type MessageFailed struct {
    MsgId string `json:"msg_id"`
    Error string `json:"error"`
}

type MessageStatus struct {
    Time    int64  `json:"time"`
    Online  *bool  `json:"online,omitempty"`
    Battery *int   `json:"battery,omitempty"`
    Rssi    *int   `json:"rssi,omitempty"`
    Ip      string `json:"ip,omitempty"`
    Version string `json:"version,omitempty"`
    Uptime  int64  `json:"uptime,omitempty"`
    Data    any    `json:"data,omitempty"`
}

TypeScript

typescript
interface MessagePending {
  sender: string;
  receiver: string;
  msg_id: string;
  action: string;
  time: number;
  exp: number;
  value?: any;
}

interface MessageAck {
  msg_id: string;
}

interface MessageProgress {
  msg_id: string;
  value: any;
}

interface MessageComplete {
  msg_id: string;
  value?: any;
}

interface MessageFailed {
  msg_id: string;
  error: string;
}

interface MessageStatus {
  time: number;
  online?: boolean;
  battery?: number;
  rssi?: number;
  ip?: string;
  version?: string;
  uptime?: number;
  data?: any;
}

物联网设备通信协议文档