Skip to content

esphome-libs/dlms_parser

dlms_parser

dlms_parser is a C++20 library for parsing DLMS/COSEM push telegrams from electricity meters.
It is designed for embedded and integration-heavy environments such as ESPHome, but it also works on desktop platforms.

Features

  • Transport decoding: RAW, HDLC, M-Bus. Auto-detects the frame format based on the leading byte. Includes multi-frame segmentation and General Block Transfer
  • Encryption: AES-128-GCM decryption and optional authentication tag verification for General-GLO-Ciphering and General-DED-Ciphering APDUs
  • Crypto Backends: Pluggable decryption backends with built-in support for mbedTLS, BearSSL, and TF-PSA
  • Pattern matching: DSL-based AXDR descriptor patterns with built-in presets and custom registration
  • Callback API: cooked callback delivers OBIS code + scaled value
  • Embedded-friendly: no heap allocation during parsing
  • Portable: builds on ESP32 (IDF/Arduino), ESP8266, Linux, macOS, Windows

How to use

Complete example with the explanation: test_example.cpp

Creating custom patterns to match your meter's telegram structure

The parser starts with no registered AXDR patterns. Load the built-ins first unless you want full control:

parser.load_default_patterns();

Built-in patterns (available after calling parser.load_default_patterns()):

Name Pattern Priority Typical use
classId-taggedObis-scaler-value TC,TO,TS,TV 10 class ID, tagged OBIS, scaler, value
taggedObis-value-scalerUnit TO,TV,TSU 20 tagged OBIS, value, scaler-unit structure
value-classId-scalerUnit-taggedObis TV,TC,TSU,TO 30 value first, class ID, scaler-unit, OBIS
zpaAidon-untaggedLayout ADV 40 untagged ZPA/Aidon-style layouts
structuredObis-value-scalerUnit S(TO, TV, TSU) 50 OBIS, value, scaler-unit structure
structuredObis-value S(TO, TV) 60 OBIS and value structure
flatObis-valuePair TO, TV 70 flat OBIS + value pairs
firstElement-dateTime F, S(TO, TDTM) 80 first-element date-time structure
swappedTagObis-value-scalerUnit TOW, TV, TSU 90 swapped-tag OBIS, value, scaler-unit

Registering Custom Patterns:

If your meter emits a layout not covered by the built-ins, you can register custom patterns. Lower priority numbers are evaluated first.

// Simple — priority 0 (tried before built-ins)
parser.register_pattern("TC, TO, TDTM");

// Named with explicit priority
parser.register_pattern("MyPattern", "TO, TV, S(TS, TU)", 5);

// With default OBIS — used when the pattern captures no OBIS code
const uint8_t meter_obis[] = {0, 0, 96, 1, 0, 255};  // 0.0.96.1.0.255
parser.register_pattern("MeterID", "L, TSTR", 0, meter_obis);

Pattern priority matters:

  • lower priority number is tried first
  • register_pattern(dsl) uses priority 0
  • built-ins start at priority 10

Common examples:

parser.register_pattern("TC, TO, TDTM");          // datetime value
parser.register_pattern("C, O, A, V, TS, TU");    // untagged flat
parser.register_pattern("TO, TV, S(TS, TU)");     // tagged with scaler-unit
parser.register_pattern("TO, TV");                // flat OBIS + value pairs (no scaler)
parser.register_pattern("L, TSTR");               // last element as string
parser.register_pattern("TOW, TV, TSU");          // Landis+Gyr swapped OBIS

Token reference

Token Meaning Hex example
F first element guard position check only
L last element guard position check only
C class ID, 2-byte uint16 without tag 00 03
TC tagged class ID 12 00 03
O OBIS code, 6-byte octet string without tag 01 00 01 08 00 FF
TO tagged OBIS code 09 06 01 00 01 08 00 FF
TOW tagged OBIS with swapped tag bytes 06 09 01 00 1F 07 00 FF
A attribute index, 1-byte uint8 without tag 02
TA tagged attribute 11 02 or 0F 02
V / TV generic value 06 00 00 07 A4
TSTR tagged string-like value 09 08 38 34 38 39 35 31 32 36
TDTM tagged 12-byte date-time value 19 ... or 09 0C ...
TS tagged scaler 0F FF
TU tagged unit enum 16 23
TSU tagged scaler-unit pair 02 02 0F FF 16 23
S(x, y, ...) inline sub-structure 02 03
DN descend into nested structure control token
UP return from nested structure control token

API Reference

DlmsParser Core Methods

⚠️ Warning: If you intend to use encryption, you must provide a concrete Aes128GcmDecryptor backend to the constructor before calling set_decryption_key or set_authentication_key. Calling these methods on a parser initialized with the default nullptr decryptor will cause a null pointer dereference.

Method Description
DlmsParser(Aes128GcmDecryptor* = nullptr) Constructor accepting an optional pointer to an AES-128-GCM decryptor backend.
set_skip_crc_check(bool) Skip CRC/checksum validation for HDLC and M-Bus.
set_decryption_key(const Aes128GcmDecryptionKey&) Set AES-128-GCM decryption key (GUEK). Requires a non-null decryptor.
set_authentication_key(const Aes128GcmAuthenticationKey&) Set AES-128-GCM authentication key (GAK) for GCM tag verification. Requires a non-null decryptor.
load_default_patterns() Register all built-in patterns (T1, T2, T3, DateTime, etc.).
ParseResult parse(std::span<uint8_t> buf, const DlmsDataCallback&) Parse a complete frame; modifies the buffer in-place and triggers the callback.

Supported APDU Tags

Common APDU tags accepted by the parser:

Byte Meaning
0x0F DATA-NOTIFICATION
0xE0 General-Block-Transfer — reassembles numbered blocks, then re-enters APDU parsing
0xDB General-GLO-Ciphering — encrypted, needs decryption key
0xDF General-DED-Ciphering — encrypted, needs decryption key
0x01 raw AXDR array
0x02 raw AXDR structure

Basic Example

#include <vector>
#include "dlms_parser.h"
#include "decryption/aes_128_gcm_decryptor_mbedtls.h"

using namespace dlms_parser;

int main() {
    // 1. Initialize a crypto backend (e.g., mbedTLS)
    Aes128GcmDecryptorMbedTls decryptor;
    
    // 2. Initialize the parser with a pointer to the decryptor
    DlmsParser parser(&decryptor);
    
    // 3. Set keys using the robust hex loader
    auto dec_key = Aes128GcmDecryptionKey::from_hex("00112233445566778899AABBCCDDEEFF");
    auto auth_key = Aes128GcmAuthenticationKey::from_hex("FFEEDDCCBBAA99887766554433221100");
    
    if (dec_key) parser.set_decryption_key(*dec_key);
    if (auth_key) parser.set_authentication_key(*auth_key);

    // 4. Load common built-in meter layout patterns
    parser.load_default_patterns();

    // 5. Provide your data (will be modified in-place during parsing)
    std::vector<uint8_t> my_telegram = { /* ... byte data ... */ };
    
    // 6. Define your callback
    auto callback = [](const char* obis, float f_val, const char* s_val, bool is_numeric) {
        printf("Matched OBIS: %s | String: %s | Float: %f\n", obis, s_val, f_val);
    };

    // 7. Parse the telegram by explicitly constructing a std::span<uint8_t>
    ParseResult result = parser.parse(std::span<uint8_t>(my_telegram.data(), my_telegram.size()), callback);
    
    printf("Successfully parsed %zu COSEM objects!\n", result.count);
    return 0;
}

Logging

dlms_parser includes a built-in logging system that is useful for debugging frame parsing and pattern matching. You can hook into it by providing a custom log function:

#include "log.h"
#include <cstdarg>
#include <cstdio>

// ... inside your setup code ...
dlms_parser::Logger::set_log_function([](dlms_parser::LogLevel level, const char* fmt, va_list args) {
    // Implement your platform-specific print here
    vprintf(fmt, args);
    printf("\n");
});

How to add the library to your project

PlatformIO package

https://registry.platformio.org/libraries/esphome/dlms_parser

ESP-IDF component

https://components.espressif.com/components/esphome/dlms_parser

CMake

FetchContent_Declare(
  dlms_parser
  GIT_REPOSITORY https://github.com/esphome-libs/dlms_parser
  GIT_TAG v1.0)
FetchContent_MakeAvailable(dlms_parser)

add_executable(your_project_name main.cpp)
target_link_libraries(your_project_name PRIVATE dlms_parser)

Acknowledgements

This library builds on foundational work and protocol insights from:

  • esphome-dlms-cosem - original ESPHome DLMS/COSEM component and AXDR parser by latonita.
  • xt211 - Sagemcom XT211 parser by Tomer27cz, instrumental in de-Guruxing the protocol handling.

References

About

No description, website, or topics provided.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Sponsor this project

Packages

 
 
 

Contributors