跳到主要内容

Sparkplug B 驱动

PlantPulse Edge 的 Sparkplug B 驱动是 MQTT 3.1.1 客户端 + Sparkplug B 负载 Protobuf 解码器 的原生 Java 实现。它不依赖外部 paho/tahu jar 包,因此在单个 jar 部署时无需额外配置即可运行。

源码:plantpulse.driver.protocol.sparkplug.*

类职责
SparkplugBDriverProtocolDriver 实现 — connect/read/write/close, alias·metric 缓存
SparkplugMqttClientMQTT 3.1.1 自包含客户端 (CONNECT / SUBSCRIBE / PUBLISH / PINGREQ)
SparkplugBPayloadSparkplug B 负载 protobuf 线性编码器/解码器 (varint / fixed32 / fixed64 / length-delim)

操作流程​

broker ──PUBLISH──> SparkplugMqttClient ──onMessage(topic, payload)──> SparkplugBDriver
│
├─ topic 파싱 (spBv1.0/G/<msgType>/edge[/dev])
├─ Payload 디코드 → metric list
├─ NBIRTH/DBIRTH 시 alias→name 등록
└─ metricCache[edge[/dev]/name] = formatValue()

PlantPulse 폴러 ──read(addr)──> metricCache[addr] (in-memory hit, 외부 RTT 없음)
write(addr, value) ──encode──> NCMD/DCMD publish → broker

选项​

键默认值说明
group-iddefaultSparkplug 组 ID。订阅时作为通配符的一部分使用。驱动会过滤掉组不匹配的消息。
edge-node-id+边缘节点过滤器。如果为 + 则包含组内所有节点。
keep-alive60MQTT 保持连接秒数。为 0 时禁用 ping。
connect-timeout5000TCP 连接超时毫秒数。

订阅主题由 spBv1.0/<group-id>/+/<edge-node-id>/# 模式构成(+ 是 message_type,# 是设备部分的通配符)。


Sparkplug 数据类型映射​

SparkplugBPayload.Metric.formatValue() 会根据在线数据类型将其转换为合适的字符串。

Sparkplug 数据类型存储字段格式化结果
Int8 / Int16 / Int32intValue (varint)有符号整数 (Integer.toString)
UInt8 / UInt16 / UInt32intValue无符号 (& 0xFFFFFFFFL)
Int64 / DateTimelongValue有符号长整数
UInt64longValueLong.toUnsignedString
FloatfloatValue (fixed32)Float.toString
DoubledoubleValue (fixed64)Double.toString
BooleanbooleanValue (varint)"true" / "false"
String / Text / UUIDstringValue按 UTF-8 原样保留
Bytes / FilebytesValue十六进制字符串

is_null=true 指标会被评估为空字符串。


NBIRTH / DBIRTH 的别名学习​

Sparkplug 效率核心:BIRTH 发送指标名称与别名对 → 之后 NDATA/DDATA 仅发送别名。

1) edge1 의 NBIRTH:
metric { name="Temperature" alias=7 datatype=Float float_value=23.5 }
→ driver: aliasByPrefix.put("edge1", {7 → "Temperature"})
metricCache.put("edge1/Temperature", "23.5")

2) edge1 의 NDATA (이름 생략):
metric { alias=7 datatype=Float float_value=24.1 }
→ driver: name 없음 → alias=7 → "Temperature"
metricCache.put("edge1/Temperature", "24.1")

如果 NDATA 在缺少 NBIRTH 的情况下到达,别名查找会失败并被忽略(不会更新缓存)。等待代理重启后发布者重新发布 NBIRTH。


NDEATH / DDEATH​

当边缘节点或设备终止时,代理会通过 LWT(遗嘱消息)发布 NDEATH/DDEATH。驱动仅清空别名映射,但保留缓存 — 最后的已知值会作为轮询结果保留(PlantPulse 的监视器会照常显示 lastValue 界面)。


NCMD / DCMD 发送​

write(ProtocolAddress) 会根据地址段的数量自动分支。

地址发布主题备注
edge1/SetPointspBv1.0/<group>/NCMD/edge1节点级命令
edge1/dev1/SetPointspBv1.0/<group>/DCMD/edge1/dev1设备级命令

阶段 1 会将所有命令以 Sparkplug 数据类型 String 发布 — 发送端(Tahu / Ignition)会根据指标定义的数据类型进行转换并处理。


限制与后续工作​

  • TLS / 认证 — 目前仅支持明文 + 匿名。用户名/密码 / mTLS 选项后续添加。
  • QoS — 所有发布/订阅均为 QoS 0。Sparkplug 推荐仅 NBIRTH 使用 QoS 1,NDATA/DDATA 使用 QoS 0。
  • DataSet / 模板指标 — 线上数据以原始字节保留(datasetRaw/templateRaw),但解码/格式化尚未实现。
  • 属性 / 元数据 — 仅保留原始字节,解码未实现。
  • bdSeq — NBIRTH 的 bdSeq 匹配 / NDEATH 验证未实现。

测试位置​

test/java/plantpulse/driver/protocol/sparkplug/SparkplugBDriverTest.java — 27 个测试。

  • 初始状态 / 选项解析
  • 未连接时的 read/write 安全性
  • BIRTH 别名注册,NDATA 仅别名解析,组不匹配阻止,DEATH 别名清理
  • 各数据类型的 formatValue 准确性 (Int32 / Float / Double / Boolean / String / UInt32 / UInt64 / is_null)
  • 负载编码→解码往返
  • MQTT 剩余长度 / UTF-8 线上工具
  • safeId clientId 清理