Skip to main content

pydlms

CI PyPI Python License Code style: ruff

A Python library for reading smart meters over DLMS/COSEM (IEC 62056), the protocol most electricity meters in Europe and many other regions speak.

pydlms talks to a meter over TCP, a serial line, an optical probe or a wired M-Bus, sets up a plain or secured association, and reads and writes COSEM objects. It also decodes the pushes that meters send on customer interfaces such as the Austrian, Dutch and Norwegian P1/HAN ports. Packets are defined with the construct library.

Status: alpha. The API may change before 1.0.

Features

  • Transports: TCP and UDP (wrapper), HDLC over TCP or serial, IEC 62056-21 optical probes including battery-meter wake-up, and wired M-Bus
  • Associations: Logical-Name and Short-Name referencing, every authentication level from none and LLS up to HLS-GMAC and ECDSA
  • Services: GET, SET, ACTION with block transfer, with-list requests, selective access, general-block-transfer and ACCESS
  • Security: suites 0, 1 and 2 (AES-GCM, ECDH, ECDSA), dedicated and broadcast keys, key transfer and agreement, certificates, invocation-counter checks, and keys kept in an HSM if you want
  • Push decoding: DataNotification, EventNotification and DSMR P1 telegrams, with profiles for Norwegian HAN, Austrian P1 and Wiener Netze
  • COSEM model: typed objects for 48 interface classes, load profiles with timestamps and scalers, access rights, an OBIS name catalogue
  • Tooling: a CLI, a frame explainer, session recording and redaction, and a built-in meter simulator to try everything without hardware

Installation

pip install pydlms-client            # core
pip install "pydlms-client[all]"     # + encryption (cryptography) and serial ports (pyserial)

The package is published as pydlms-client because pydlms is too close to an existing PyPI name. You still import pydlms.

Usage

Read a few values from a meter's public client:

from pydlms import DlmsClient

with DlmsClient.tcp("192.0.2.10", 4059) as meter:
    print(meter.get_register("1.0.1.8.0.255"))    # 12345678 Wh
    print(meter.get_clock())
    for entry in meter.get_association_view():
        print(entry)

A secured association (HLS-GMAC, suite 0) over HDLC on a serial port:

from pydlms import DlmsClient, Mechanism, SecurityContext

security = SecurityContext(
    encryption_key=bytes.fromhex("000102030405060708090A0B0C0D0E0F"),
    authentication_key=bytes.fromhex("D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"),
    client_system_title=b"PYDLMS01",
    invocation_counter=1234,     # continue from the meter's last counter
)
with DlmsClient.serial("/dev/ttyUSB0", 9600, client_sap=1,
                       mechanism=Mechanism.HLS_GMAC, security=security) as meter:
    profile = meter.read_profile("1.0.99.1.0.255", typed=True, scalers=True)
    for stamp, energy in profile.rows:
        print(stamp.to_datetime(), energy)

Decode the encrypted pushes from a customer interface:

from pydlms import PushDecoder, SecurityContext
from pydlms.profiles import get_profile
from pydlms.security.suites import SecurityPolicy

security = SecurityContext(bytes.fromhex("36C6..."), policy=SecurityPolicy.ENCRYPTED)
decoder = PushDecoder("mbus", security, profile=get_profile("netz-noe-p1"))
for message in decoder.feed(serial_bytes):
    print(message.get("1.0.1.8.0.255"), message.get("1.0.32.7.0.255"))

DlmsClient.optical() and DlmsClient.mbus() work the same way for optical probes and wired M-Bus.

More:

  • examples/ has runnable scripts for each topic. They use the built-in simulator unless you point them at a meter.
  • GUIDE.md covers connection options, security (suites 1/2, key management, HSMs, broadcast), pushes, companion standards, the CLI and debugging in detail.

CLI

pydlms read tcp://192.0.2.10:4059 --obis 1.0.1.8.0.255 --register
pydlms profile serial:///dev/ttyUSB0?baud=9600 --obis 1.0.99.1.0.255 --last 4
pydlms push /dev/ttyUSB0 --framing mbus --key 36C666... --profile netz-noe-p1
pydlms decode 7EA08BCEFF0313EEE1E6E700E04000... --key ... --auth-key ...
pydlms simulate --port 4059        # a local meter to try things against

Debugging a meter

-v logs every frame and APDU, -vv adds hexdumps. --record session.hex saves a session; pydlms decode --file session.hex explains it layer by layer, pydlms simulate --replay session.hex serves it again as a test meter, and pydlms redact removes serial numbers, system titles and secrets before you share it. Keys never appear in logs or repr.

Verification status

pydlms is an unofficial implementation. It is checked against public sources and other implementations, not certified: DLMS UA certifies meters, and no certification exists for client libraries.

  • Target editions: Green Book Ed. 12 (IEC 62056-5-3:2023) and Blue Book Ed. 17, written from the public DLMS UA excerpts, national adoptions, companion standards and published test vectors. Details no public source confirms are marked unverified in the code.
  • Cross-checked against Gurux (.NET and C), OpenMUC jDLMS, cB-Sigma dlms, dlms-cosem, the Rust DLMS crates and opendlms, with Wireshark decoding the frames pydlms builds, and 16 real meter push captures.
  • Not yet: tested in a live session with a real meter. Push setup v3, Disconnect control v2 and the Attestation class from recent Blue Book editions are not modelled yet.

Reports from real meters help most: please use the meter compatibility issue template. Only connect to meters you own or are authorised to read.

Development

git clone https://github.com/f0rw4rd/pydlms.git
cd pydlms
pip install -e ".[dev]"
pytest                    # unit, crypto known-answer tests, real captures, end to end
pytest -m integration     # serial PTY, Gurux simulator, interop peers (Docker)

See CONTRIBUTING.md before opening a pull request.

Support

If you find this project useful, consider supporting development:

Ko-fi

License

Dual-licensed under GPL-3.0 and a commercial license.

Free for open source use under GPL-3.0. If you want to use pydlms in proprietary products without GPL obligations, a commercial license is available. Third-party test vectors and reference material are listed in THIRD_PARTY.md.

Trademarks

All marks belong to their owners; used nominatively to describe interoperability; no endorsement implied.

Metadata

Release files for pydlms-client 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pydlms-client 0.1.0
File Size Uploaded Provenance Actions
pydlms_client-0.1.0.tar.gz 892.7 kB With provenance Details for pydlms_client-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pydlms-client 0.1.0
File Interpreter ABI Platform Actions
pydlms_client-0.1.0-py3-none-any.whl Python 3 none any Details for pydlms_client-0.1.0-py3-none-any.whl

Total release size: 1.3 MB

Release files / pydlms_client-0.1.0.tar.gz

Download URL pydlms_client-0.1.0.tar.gz
Size 892.7 kB
Tags Source
SHA-256 checksum
How to use checksums
75fca74c00e6e9e504a4c672014c7b2b304b26e4e0e83a09262a041cba1e5135
BLAKE2b-256 checksum
How to use checksums
85fa4ea79bf09eb83512aaab582ae39261f97124fc2a0eca2da2071e94048730
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / pydlms_client-0.1.0-py3-none-any.whl

Download URL pydlms_client-0.1.0-py3-none-any.whl
Size 397.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0ff076858f589a162339c68336c63dd15b6cd18a56abcc8d9482d43d49587b18
BLAKE2b-256 checksum
How to use checksums
b785e062ff012bbee81dd846a232f93c083df0a5d1766059e3892eaa90a87c4e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Security for pydlms-client 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pydlms_client-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page