跳到主要内容

M-Bus 驱动

概述

M-Bus (Meter-Bus, EN 13757-2/3) 的自研 Java native 实现。可通过 TCP socket 连接到运行环境中常见的 wired M-Bus master 网关或串口-TCP 转换器 (Moxa NPort、USR-TCP232 等),收发标准 M-Bus 帧。

项目
opc_typeMBUS
实现类plantpulse.driver.protocol.mbus.MBusDriver
(无 — 自研实现。EN 13757-2/3)
read良好 (REQ_UD2 → RSP_UD)
write良好 (Slave Selection / Application Reset)
默认端口10001 (Moxa NPort 默认)
安全

类 / 结构

MBusDriver (BaseProtocolDriver)
├── Socket / DataInputStream / OutputStream
├── defaultAddress — primary 1~250 (옵션)
├── synchronized requestUd2 / sendSlaveSelection / sendAppReset
├── MBusFrame — buildSndNke / buildReqUd2 / buildSlaveSelection
│ buildSndUdAppReset / parseLongFrame / parseAck
│ ACK=0xE5, START_LONG=0x68, SECONDARY_ADDRESS=253
├── MBusChecksum — sum(c+a+ci+data) mod 256
├── MBusBcd — encodeIdToBcd4(long), BCD 디코드
└── MBusDataRecord — DIF/VIF 파싱, parseAll(buf, off, len) → List<Record>
(Record { value, multiplier, unit, ... })

connect() :

  1. TCP 连接 (host:10001)。
  2. 发送 SND_NKE (Short Frame, C=0x40, A=default-address)。
  3. 校验收到的 ACK (0xE5) — 即使无响应也置 connected=true (各网关存在差异)。

wire 格式摘要

Short Frame (SND_NKE / Slave Selection 响应 ACK)

0x10 | C(1) | A(1) | CS(1) | 0x16
ACK 단독 = 0xE5

Long Frame (REQ_UD2 / RSP_UD)

0x68 | L | L | 0x68 | C(1) | A(1) | CI(1) | data... | CS(1) | 0x16
L = C + A + CI + data 의 byte 수
CS = (C+A+CI+data) mod 256
命令CCI含义
SND_NKE0x40Initialize slave
REQ_UD20x5B请求 User data
Slave Selection0x530x52Secondary addressing
App Reset0x530x50Application reset

OPC 注册选项 (options)

含义默认值
default-addressprimary address (1~250)1
connect-timeoutms3000
read-timeoutms3000

标签地址格式

Primary addressing

表示含义
1:0primary 1,第一个 record
5:2primary 5,第三个 record
1primary 1,全部 user-data hex

Secondary addressing

表示含义
secondary:12345678AB1C010716 位 hex 字符 (ID 4 + Mfg 2 + Ver 1 + Med 1)
secondary:<16-hex>:<recordIndex>上述 + record 索引
select:12345678:43932:1:7十进制别名 (id, mfg, ver, med)
select:12345678:43932:1:7:0+ record 索引

trySecondaryAddress() 先发送 secondary slave selection → 再以 primary=253 执行 REQ_UD2。 ID 按 EN 13757-3 wire format 的 LSB-first BCD 编码 (MBusBcd.encodeIdToBcd4)。

write 地址格式

表示动作
secondary:<hex> / select:<id>:<mfg>:<ver>:<med>仅发送 Slave selection
app-reset:<subcode>对 primary=default-address 执行 application reset
app-reset:<primary>:<subcode>显式指定 primary
select-and-reset:<id>:<mfg>:<ver>:<med>:<subcode>选择 secondary 后 reset

subcode 也可以用 address.value 形式传入。


record 解码

MBusDataRecord.parseAll(userData, off=12, len) 基于 DIF/VIF 遍历 user-data (header 12 byte 之后),返回 Record { value, multiplier, unit, ... } 列表。

formatValue(record) :

  • 整数 + multiplier=1 → Long.toString(...)
  • Number → value * multiplier (double)
  • 其他 → String.valueOf(value)

支持 / 不支持

  • ✅ SND_NKE → REQ_UD2 → RSP_UD 周期
  • ✅ Primary addressing (1~250)
  • ✅ Secondary addressing (slave selection + primary 253 read)
  • ✅ Application Reset (CI=0x50)
  • ✅ DIF/VIF data record 解析 + multiplier 缩放
  • ❌ FCB (frame count bit) toggle / Multi-frame UD2
  • ❌ Wireless M-Bus (EN 13757-4)
  • ❌ Encryption (mode 5 / 7 — 智能电表)

测试覆盖率

test/java/plantpulse/driver/protocol/mbus/

测试数
MBusAckTest4
MBusBcdTest13
MBusChecksumTest4
MBusDataRecordTest7
MBusDriverAddressTest10
MBusDriverWriteTest9
MBusFrameTest14
MBusSpecExtraTest28

共 89 个测试。


参考

  • EN 13757-2 Physical and link layer
  • EN 13757-3 Application layer / DIF/VIF / Secondary addressing
  • 代码: src/plantpulse/driver/protocol/mbus/