M-Bus Gateway
← Tilbage til blog
· OMS· EN 13757· wM-Bus· telegram· protokol· HCA· fabrikant-ID· DIB· VIB· parsing

OMS standard EN 13757 — wM-Bus telegram-format fra bund til top

OMS (Open Metering System) og EN 13757: Layer-model, telegram-header, DIB/VIB datastruktur, fabrikant-ID, medietypes og praktisk byte-for-byte parsing.

Af M-Bus Gateway

OMS (Open Metering System) er den åbne standard bag alle interoperable wM-Bus-målere. Her er telegram-formatet fra bund til top.


OMS og EN 13757: Relationen

EN 13757 (CENELEC standard):
  EN 13757-2: Fysisk lag og datalink-lag (M-Bus wired)
  EN 13757-3: Applikationslag (data-struktur, DIB/VIB)
  EN 13757-4: Trådløs M-Bus (wM-Bus) — radio-lag
  EN 13757-5: Kryptografi (AES-128)
  EN 13757-7: Transport og nætværkslag

OMS (Open Metering System):
  → Industriens profildokument oven på EN 13757
  → Specificerer hvilke EN-13757-3 VIF/VIFE der bruges pr. måletype
  → Definerer krypteringskrav pr. mode (Mode 5 = AES-128 CTR)
  → OMS-Volume 2: Profiler for HCA, varmemåler, vandmåler, gasmåler
  → Overholdelse = interoperabilitet (enhver OMS-gateway kan læse enhver OMS-måler)

Telegram-struktur: Byte-for-byte

Komplet wM-Bus C1/T1 telegram (hex):
  27 44 93 15 78 56 34 12 03 07 8C 20 77 AB 1C 3E 22 ...

Offset  Bytes  Felt              Forklaring
──────  ─────  ────────────────  ──────────────────────────────────────
0       01     L (Length)        27h = 39 bytes total telegram-længde
1       01     C (C-field)       44h = SND-NR (Send No Reply, T1/C1)
2       02     M (Manufacturer)  9315h = "ELS" (Engelmann)
4       04     A (Address)       78563412h = Serienummer (LSB first) = 12345678
8       01     Ver (Version)     03h = firmwareversion
9       01     Type (Media)      07h = vandmåler (07=vand, 04=varme, 08=HCA)
10      02     CI (Control Info) 8C20h = Long Transport Layer header
12      rest   Payload           Krypteret eller klar tekst data

Medietypes (EN 13757-4, tabel 5):
  01 = Elektricitet
  03 = Gas
  04 = Varmemåler
  06 = Vandvarmer
  07 = Vand (koldtvandsmåler)
  08 = HCA (Heat Cost Allocator)
  0A = Køling
  0B = Kombination: køle + varme
  0C = Varmt brugsvand
  16 = El (alternativ)

Fabrikant-ID: M-felt dekodning

def decode_manufacturer_id(m_bytes: bytes) -> str:
    """
    Dekod 2-byte fabrikant-ID til 3-bogstavers kode.
    EN 13757-4 § 6.4.3

    Encoding: 5-bit per bogstav, packed i 16 bit (little-endian)
    A=1, B=2, ..., Z=26 (kun store bogstaver)

    Eksempler:
      ELS = Engelmann:  9315h
      KAM = Kamstrup:   2C2Dh
      TCH = Techem:     6850h
      DIE = Diehl:      A324h
      ZRI = Zenner:     F732h
    """
    m_val = int.from_bytes(m_bytes, "little")
    # Bit 15-11: bogstav 1, 10-6: bogstav 2, 5-1: bogstav 3
    c1 = chr(((m_val >> 10) & 0x1F) + 64)
    c2 = chr(((m_val >> 5) & 0x1F) + 64)
    c3 = chr((m_val & 0x1F) + 64)
    return f"{c1}{c2}{c3}"

# Test:
assert decode_manufacturer_id(bytes.fromhex("9315")) == "ELS"
assert decode_manufacturer_id(bytes.fromhex("2C2D")) == "KAM"
assert decode_manufacturer_id(bytes.fromhex("6850")) == "TCH"

DIB/VIB: Applikationslag-datastruktur

DIB (Data Information Block) + VIB (Value Information Block):
  → Hvert datapunkt i payload er en DIB+VIB+data tripel
  → Kan gentages N gange (mange datapunkter pr. telegram)

DIB-byte (Data Information Block):
  Bit 7-6: DIF Extension (00=normal, 01=special)
  Bit 5-4: Function Field (00=Instantaneous, 01=Maximum, 10=Minimum, 11=Error)
  Bit 3-0: Data Field (0000=None, 0001=8bit, 0010=16bit, 0100=32bit, 0110=48bit, 1100=date, 1101=string)

VIB-byte (Value Information Block):
  Bit 7: VIF Extension (0=tabel A, 1=tabel B eller VIFE)
  Bit 6-0: VIF-kode

Vigtige VIF-koder (EN 13757-3, tabel A):
  00h-07h: Energi (kWh, MWh)
  10h-17h: Volumen (m³, l)
  40h-43h: Temperatur (°C)
  20h-27h: On Time / Operating Time
  6Dh:     Dato + tid (6-byte)
  78h:     Fabrikantspecifik
  79h:     OBIS-kode reference

Eksempel: Energidata (32-bit, kWh):
  04  →  DIB: 32-bit integer, instantaneous
  04  →  VIB: Energi, enhed: 1 × 10^(0-3) Wh = 0.001 kWh
  B0 36 00 00  →  Data: 0x000036B0 = 14.000 = 14.000 × 0.001 kWh = 14 kWh

Kryptografi: OMS Mode 5

# OMS kryptering Mode 5 = AES-128 CTR (Counter Mode)
# Nøgle: 16 bytes AES-nøgle (leveret af fabrikant ved installation)
# IV: Bygget fra telegram-header-felter

from Crypto.Cipher import AES

def decrypt_oms_mode5(
    ciphertext: bytes,
    aes_key: bytes,
    manufacturer_id: bytes,  # 2 bytes M-felt
    address: bytes,           # 4 bytes A-felt (serienummer)
    version: int,             # 1 byte Ver
    media_type: int,          # 1 byte Type
) -> bytes:
    """
    Dekryptér OMS Mode 5 (AES-128 CTR).
    IV = M(2) + A(4) + Ver(1) + Type(1) + 08*(8)
    """
    iv = manufacturer_id + address + bytes([version, media_type]) + b"\x08" * 8
    cipher = AES.new(aes_key, AES.MODE_CTR, nonce=b"", initial_value=iv)
    return cipher.decrypt(ciphertext)

# wmbusmeters håndterer dette automatisk ved key-konfiguration:
# key = AES-nøgle i hex pr. meter (fra fabrikant)

OMS-profil: HCA (Heat Cost Allocator)

OMS Volume 2, Profil HCA:
  Krævet data:
    - Aktuelt HCA-tal (DIB=04, VIB=6E) — units
    - Forrige HCA-tal (DIB=44, VIB=6E, Function=01) — units
    - Forrige periode start (dato)
    - Aktuelt dato/tid
    - Serienummer radiator (fabrikantspecifik)

  Valgfrit:
    - RSSI (modtagefeltsvurdering)
    - Batteriniveau
    - Fejlkoder (defekt, fjernet, sabotage-alarm)

Typisk OMS HCA telegram (wmbusmeters JSON output):
{
  "media": "heat_cost_allocator",
  "meter": "sensostar",
  "name": "Lej1Radiator",
  "id": "66073591",
  "current_hca": 312,           ← Aktuelt tal (DIB=04, VIB=6E)
  "previous_hca": 285,          ← 1. jan foregående år
  "set_date": "2025-01-01",     ← Periodestart
  "rssi_dbm": -72,
  "battery_ok": true,
}

Konklusion

OMS/EN 13757 definerer en åben, interoperabel standard for forbrugsmålere. Telegram-strukturen er hierarkisk: fysisk lag (868MHz) → datalink (CRC) → transport (header med M/A/Ver/Type) → applikation (DIB/VIB datapar). Fabrikant-ID dekodes fra 2 bytes til 3-bogstavers kode. AES-128 CTR Mode 5 krypterer payload med IV bygget fra header-felter.

Se wM-Bus telegram parsing guide eller AES-128 CTR dekryptering guide.