M-Bus Treiber
Übersicht
Eigene native Java-Implementierung von M-Bus (Meter-Bus, EN 13757-2/3). Die Anbindung erfolgt per TCP-Socket an ein in der Praxis übliches Wired-M-Bus-Master-Gateway oder an einen Seriell-TCP-Konverter (Moxa NPort, USR-TCP232 usw.), um standardkonforme M-Bus-Frames zu senden und zu empfangen.
| Punkt | Wert |
|---|---|
opc_type | MBUS |
| Implementierungsklasse | plantpulse.driver.protocol.mbus.MBusDriver |
| Bibliothek | (keine — Eigenimplementierung. EN 13757-2/3) |
| read | gut (REQ_UD2 → RSP_UD) |
| write | gut (Slave Selection / Application Reset) |
| Standardport | 10001 (Moxa NPort Standard) |
| Sicherheit | keine |
Klassen / Struktur
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-Verbindung (host:10001).
- SND_NKE (Short Frame, C=0x40, A=
default-address) senden. - Empfang von ACK (0xE5) prüfen — auch ohne Antwort gilt connected=true (je nach Gateway unterschiedlich).
Zusammenfassung des Wire-Formats
Short Frame (SND_NKE / ACK auf Slave Selection)
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
| Befehl | C | CI | Bedeutung |
|---|---|---|---|
| SND_NKE | 0x40 | — | Initialize slave |
| REQ_UD2 | 0x5B | — | User-Data-Anforderung |
| Slave Selection | 0x53 | 0x52 | Secondary addressing |
| App Reset | 0x53 | 0x50 | Application reset |
OPC-Registrierungsoptionen (options)
| Schlüssel | Bedeutung | Standard |
|---|---|---|
default-address | primary address (1~250) | 1 |
connect-timeout | ms | 3000 |
read-timeout | ms | 3000 |
Tag-Adressformat
Primary addressing
| Notation | Bedeutung |
|---|---|
1:0 | primary 1, erster Record |
5:2 | primary 5, dritter Record |
1 | primary 1, gesamte User-Data als Hex |
Secondary addressing
| Notation | Bedeutung |
|---|---|
secondary:12345678AB1C0107 | 16 Hex-Zeichen (ID 4 + Mfg 2 + Ver 1 + Med 1) |
secondary:<16-hex>:<recordIndex> | wie oben + Record-Index |
select:12345678:43932:1:7 | dezimaler Alias (id, mfg, ver, med) |
select:12345678:43932:1:7:0 | + Record-Index |
trySecondaryAddress() sendet zuerst die Secondary Slave Selection → anschließend REQ_UD2 mit primary=253.
Die ID wird im Wire-Format nach EN 13757-3 als LSB-first BCD codiert (MBusBcd.encodeIdToBcd4).
write-Adressformat
| Notation | Verhalten |
|---|---|
secondary:<hex> / select:<id>:<mfg>:<ver>:<med> | nur Slave Selection senden |
app-reset:<subcode> | Application Reset an primary=default-address |
app-reset:<primary>:<subcode> | primary explizit angegeben |
select-and-reset:<id>:<mfg>:<ver>:<med>:<subcode> | Reset nach Secondary-Auswahl |
Der subcode kann auch als address.value übergeben werden.
Record-Decodierung
MBusDataRecord.parseAll(userData, off=12, len) durchläuft die User-Data (ab Byte 12 nach dem Header) auf Basis von DIF/VIF und liefert eine Record { value, multiplier, unit, ... }-Liste zurück.
formatValue(record) :
- Ganzzahl + multiplier=1 →
Long.toString(...) - Number →
value * multiplier(double) - sonstige →
String.valueOf(value)
Unterstützt / nicht unterstützt
- ✅ Zyklus SND_NKE → REQ_UD2 → RSP_UD
- ✅ Primary addressing (1~250)
- ✅ Secondary addressing (Slave Selection + Read mit primary 253)
- ✅ Application Reset (CI=0x50)
- ✅ Parsing von DIF/VIF-Data-Records + Multiplier-Skalierung
- ❌ FCB (frame count bit) Toggle / Multi-Frame UD2
- ❌ Wireless M-Bus (EN 13757-4)
- ❌ Verschlüsselung (Mode 5 / 7 — Smart Meter)
Testabdeckung
test/java/plantpulse/driver/protocol/mbus/
| Klasse | Anzahl Tests |
|---|---|
MBusAckTest | 4 |
MBusBcdTest | 13 |
MBusChecksumTest | 4 |
MBusDataRecordTest | 7 |
MBusDriverAddressTest | 10 |
MBusDriverWriteTest | 9 |
MBusFrameTest | 14 |
MBusSpecExtraTest | 28 |
Insgesamt 89 Tests.
Referenzen
- EN 13757-2 Physical and link layer
- EN 13757-3 Application layer / DIF/VIF / Secondary addressing
- Code:
src/plantpulse/driver/protocol/mbus/