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
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.
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.
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.
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.