M-Bus Driver
Overview
A proprietary Java native implementation of M-Bus (Meter-Bus, EN 13757-2/3). It connects over a TCP socket to a wired M-Bus master gateway or a serial-to-TCP converter (Moxa NPort, USR-TCP232, etc.) commonly found in production environments, and exchanges standard M-Bus frames.
| Item | Value |
|---|---|
opc_type | MBUS |
| Implementation class | plantpulse.driver.protocol.mbus.MBusDriver |
| Library | (none — proprietary implementation. EN 13757-2/3) |
| read | Good (REQ_UD2 → RSP_UD) |
| write | Good (Slave Selection / Application Reset) |
| Default port | 10001 (Moxa NPort default) |
| Security | None |
Classes / Structure
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() :
- TCP connection (host:10001).
- Send SND_NKE (Short Frame, C=0x40, A=
default-address). - Verify ACK (0xE5) reception — connected=true even without a reply (varies by gateway).
Wire Format Summary
Short Frame (SND_NKE / Slave Selection response 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
| Command | C | CI | Meaning |
|---|---|---|---|
| SND_NKE | 0x40 | — | Initialize slave |
| REQ_UD2 | 0x5B | — | User data request |
| Slave Selection | 0x53 | 0x52 | Secondary addressing |
| App Reset | 0x53 | 0x50 | Application reset |
OPC Registration Options (options)
| Key | Meaning | Default |
|---|---|---|
default-address | primary address (1–250) | 1 |
connect-timeout | ms | 3000 |
read-timeout | ms | 3000 |
Tag Address Format
Primary addressing
| Notation | Meaning |
|---|---|
1:0 | primary 1, first record |
5:2 | primary 5, third record |
1 | primary 1, entire user-data hex |
Secondary addressing
| Notation | Meaning |
|---|---|
secondary:12345678AB1C0107 | 16 hex characters (ID 4 + Mfg 2 + Ver 1 + Med 1) |
secondary:<16-hex>:<recordIndex> | above + record index |
select:12345678:43932:1:7 | decimal alias (id, mfg, ver, med) |
select:12345678:43932:1:7:0 | + record index |
trySecondaryAddress() first sends a secondary slave selection → then REQ_UD2 with primary=253.
The ID is encoded as LSB-first BCD per the EN 13757-3 wire format (MBusBcd.encodeIdToBcd4).
Write Address Format
| Notation | Action |
|---|---|
secondary:<hex> / select:<id>:<mfg>:<ver>:<med> | Send slave selection only |
app-reset:<subcode> | Application reset to primary=default-address |
app-reset:<primary>:<subcode> | primary specified explicitly |
select-and-reset:<id>:<mfg>:<ver>:<med>:<subcode> | Reset after secondary selection |
The subcode may also be given as address.value.
Record Decoding
MBusDataRecord.parseAll(userData, off=12, len) walks the user data (after the 12-byte header) based on DIF/VIF and returns a Record { value, multiplier, unit, ... } list.
formatValue(record) :
- Integer + multiplier=1 →
Long.toString(...) - Number →
value * multiplier(double) - Otherwise →
String.valueOf(value)
Supported / Not Supported
- ✅ SND_NKE → REQ_UD2 → RSP_UD cycle
- ✅ Primary addressing (1–250)
- ✅ Secondary addressing (slave selection + primary 253 read)
- ✅ Application Reset (CI=0x50)
- ✅ DIF/VIF data record parsing + multiplier scaling
- ❌ FCB (frame count bit) toggle / Multi-frame UD2
- ❌ Wireless M-Bus (EN 13757-4)
- ❌ Encryption (mode 5 / 7 — smart meters)
Test Coverage
test/java/plantpulse/driver/protocol/mbus/
| Class | Test Count |
|---|---|
MBusAckTest | 4 |
MBusBcdTest | 13 |
MBusChecksumTest | 4 |
MBusDataRecordTest | 7 |
MBusDriverAddressTest | 10 |
MBusDriverWriteTest | 9 |
MBusFrameTest | 14 |
MBusSpecExtraTest | 28 |
89 tests in total.
References
- EN 13757-2 Physical and link layer
- EN 13757-3 Application layer / DIF/VIF / Secondary addressing
- Code:
src/plantpulse/driver/protocol/mbus/