Loading header...

DLMS/COSEM is a layered protocol. Understanding how data is packed, sent, and unpacked at each layer helps you debug real-world communication problems.

The DLMS Stack

graph TB A["Application Layer\n(COSEM objects, GET/SET/ACTION)"] B["Presentation Layer\nxDLMS encoding / ASN.1 BER"] C["Session Layer\nApplication Association — AARQ/AARE"] D["Transport Layer\nHDLC or TCP/IP wrapper"] E["Physical Layer\nRS-232 / RS-485 / PLC / TCP socket"] A --> B --> C --> D --> E

HDLC Framing

When using a serial link (optical port, RS-485), DLMS uses HDLC (High-Level Data Link Control) framing. An HDLC frame looks like this:

| FLAG | Addr | Ctrl | Info (APDU) | FCS | FLAG |
  7E     ...    ...     xDLMS data   CRC   7E
  • FLAG = 0x7E — marks frame boundaries
  • Addr — source and destination addresses (meter + HES logical addresses)
  • FCS — 16-bit CRC for error detection
  • Info — the actual DLMS Application Protocol Data Unit (APDU)

TCP/IP Wrapper

When communicating over Ethernet, cellular, or PLC with IP support, HDLC is replaced by a simple wrapper. A 6-byte header is prepended:

| Version (1B) | Length (2B) | APDU... |
     0x00 0x01     n bytes

This is sometimes called IANA port 4059 (the registered DLMS port).

Association: AARQ and AARE

Before any data exchange, an application association must be established. This is the application-layer equivalent of a TCP handshake.

sequenceDiagram participant C as Client (HES) participant S as Server (Meter) C->>S: AARQ\n(protocol version, security, calling AP title) S-->>C: AARE result=accepted\n(negotiated params, server AP title) Note over C,S: Association established C->>S: GET.request (OBIS=1.0.1.8.0.255) S-->>C: GET.response (value=12345.67 kWh) C->>S: SET.request (clock OBIS, new time) S-->>C: SET.response result=success C->>S: ACTION.request (disconnect switch) S-->>C: ACTION.response result=success C->>S: RLRQ (release association) S-->>C: RLRE

GET Service — Reading Data

A GET request specifies:

  • The class ID and instance ID (OBIS) of the object
  • The attribute index (1 = logical name, 2 = value, 3 = scaler/unit for registers)

Example: read the value of the active energy register:

GET.request {
  class_id: 3  (Register)
  instance_id: 1.0.1.8.0.255
  attribute_id: 2  (value)
}

GET.response {
  result: success
  data: DOUBLE-LONG-UNSIGNED 12345670  (raw integer)
  scaler: -2  (multiply by 10^-2)
  unit: 30    (Wh)
}
→ 12345670 × 10⁻² Wh = 123456.70 Wh = 123.46 kWh

SET Service — Writing Data

SET is used to configure the meter — set the clock, configure tariff schedules, update billing parameters.

sequenceDiagram participant C as Client participant S as Meter C->>S: SET.request\n(clock OBIS 0.0.1.0.0.255, attr 2, new datetime) S-->>C: SET.response result=0 (success)

Not all attributes are writable. The meter's association objects define which attributes each access level can SET.

ACTION Service — Invoking Methods

ACTION calls a method on an object. Example: trigger the remote disconnect relay.

sequenceDiagram participant C as Client participant S as Meter C->>S: ACTION.request\n(class 70, OBIS 0.0.96.3.10.255, method 1=remote_disconnect) S-->>C: ACTION.response result=success Note over S: Relay opens, supply cut

xDLMS Encoding

The data inside every APDU is encoded using xDLMS — a compact binary encoding based on ASN.1 BER. Each value carries a type tag:

Tag Type
0x09 Octet-string
0x0A Visible-string
0x0F Integer (8-bit)
0x10 Long (16-bit)
0x12 Long-Unsigned
0x06 Double-Long-Unsigned (32-bit)
0x14 Long64 (64-bit)
0x01 Array
0x02 Structure

Key Takeaway

DLMS is a layered stack. When debugging: check the physical link first (HDLC flags, CRC errors), then the association (AARE result codes), then the service response (GET/SET/ACTION result). Most real-world issues are either authentication failures at association or wrong OBIS codes in GET requests.