본문으로 건너뛰기

M-Bus 드라이버

개요

M-Bus (Meter-Bus, EN 13757-2/3) 의 자체 자바 native 구현. 운영 환경에서 흔한 wired M-Bus master 게이트웨이 또는 시리얼-TCP 컨버터 (Moxa NPort, USR-TCP232 등) 에 TCP socket 으로 연결해 표준 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_UD20x5BUser 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) 가 user-data (header 12 byte 이후) 를 DIF/VIF 기반으로 순회하며 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/