Skip to main content

Python library for parsing and verifying OCMF (Open Charge Metering Format) signatures from electric vehicle charging stations

Project description

PyOCMF

Python library for parsing, validating, and verifying OCMF (Open Charge Metering Format) signatures from electric vehicle charging stations.

Note: This is an unofficial library that implements parts of the OCMF specification. It is not affiliated with or endorsed by S.A.F.E. e.V.. For official verification of charging session data, please use the Transparenzsoftware provided by S.A.F.E. e.V. This library may be incomplete or contain discrepancies from the official specification.

Features

  • Parse OCMF strings into validated Python objects
  • Verify cryptographic signatures for data integrity
  • Support for ECDSA with multiple curves (secp192r1, secp256r1, secp384r1, secp521r1, brainpool variants)
  • Type-safe validation using Pydantic
  • Eichrecht compliance validation for German calibration law requirements

Installation

Recommended (Full Installation)

pip install pyocmf[all]

This installs the complete package with CLI tools and cryptographic signature verification.

Minimal Installation (parsing only)

pip install pyocmf

This installs only the core library for parsing and validating OCMF data (no CLI or crypto).

Partial Installations

# With CLI only
pip install pyocmf[cli]

# With crypto only
pip install pyocmf[crypto]

# With both CLI and crypto
pip install pyocmf[cli,crypto]

Quick Start

Parsing OCMF Data

from pyocmf import OCMF

# Parse an OCMF string
ocmf_string = 'OCMF|{"FV":"1.0","GI":"KEBA_KCP30",...}|{"SD":"3045..."}'
ocmf = OCMF.from_string(ocmf_string)

# Hex-encoded strings are automatically detected and decoded
ocmf = OCMF.from_string('4f434d467c7b2246...')

# Access payload data
print(ocmf.payload.GI)  # Gateway ID: "KEBA_KCP30"
print(ocmf.payload.GS)  # Gateway serial number
print(ocmf.payload.RD)  # List of meter readings

# Serialize back to string
print(ocmf.to_string())           # Plain OCMF string
print(ocmf.to_string(hex=True))   # Hex-encoded

Command Line Interface

PyOCMF includes a CLI for validation and signature verification.

Note: The CLI requires the cli extras. Install with pip install pyocmf[cli] or pip install pyocmf[all].

# Validate an OCMF string
ocmf 'OCMF|{"FV":"1.0",...}|{"SD":"3045..."}'

# Validate with detailed output
ocmf 'OCMF|{...}|{...}' --verbose

# Validate and verify signature
ocmf 'OCMF|{...}|{...}' --public-key 3059301306072A8648CE3D...

# Validate hex-encoded OCMF (auto-detected)
ocmf 4f434d467c7b...

# Validate from XML file (auto-detected, extracts public key for verification)
ocmf charging_session.xml

# Validate all OCMF entries in XML file
ocmf charging_session.xml --all

# Show help
ocmf --help

Example output:

✓ Successfully parsed OCMF string
✓ OCMF validation passed
✓ Signature verification: VALID
  Algorithm:    ECDSA-secp256r1-SHA256
  Encoding:     hex

Verifying Signatures

Note: Signature verification requires the crypto extras. Install with pip install pyocmf[crypto] or pip install pyocmf[all].

Important: Per the OCMF specification, public keys must be transmitted out-of-band (separately from the OCMF data itself), typically via a central register. The public key is never embedded in the OCMF string.

from pyocmf import OCMF

# Parse OCMF data
ocmf = OCMF.from_string(ocmf_string)

# Verify signature with public key (obtained separately, e.g., from XML file or registry)
public_key_hex = "3059301306072A8648CE3D020106082A8648CE3D03010703420004..."

try:
    is_valid = ocmf.verify_signature(public_key_hex)
    if is_valid:
        print("✓ Signature is valid")
    else:
        print("✗ Signature is invalid")
except ImportError:
    print("Install cryptography package: pip install pyocmf[crypto]")

Working with Public Key Metadata

The library can extract structured metadata from public keys per OCMF spec Table 23:

from pyocmf import PublicKey

# Parse public key (accepts hex or base64 encoding, auto-detected)
public_key = PublicKey.from_string(public_key_hex)
print(f"Key Type: {public_key.key_type_identifier}")
print(f"Curve: {public_key.curve}")
print(f"Key Size: {public_key.key_size} bits")
print(f"Block Length: {public_key.block_length} bytes")

# Export key in different formats
print(public_key.to_string())             # hex (default)
print(public_key.to_string(base64=True))  # base64

# Validate key matches signature algorithm
from pyocmf import OCMF
ocmf = OCMF.from_string(ocmf_string)
matches = public_key.matches_signature_algorithm(ocmf.signature.SA)
print(f"Key matches algorithm: {matches}")

Regulatory Compliance Checking

PyOCMF includes validation for German Eichrecht (calibration law) requirements:

from pyocmf import OCMF, check_eichrecht_transaction

# Check a complete transaction (begin + end)
ocmf_begin = OCMF.from_string(begin_string)
ocmf_end = OCMF.from_string(end_string)

issues = check_eichrecht_transaction(ocmf_begin, ocmf_end)

if not issues:
    print("✓ Transaction is Eichrecht compliant")
else:
    for issue in issues:
        print(f"✗ {issue}")

Checks include meter status, error flags, time sync, cable loss compensation, transaction consistency, value progression, and user identification.

Working with XML Files

OCMF data is often distributed in XML format (e.g. when downloading transaction data from a CPO backend). PyOCMF provides utilities to extract and verify OCMF data from these files.

from pyocmf import OcmfContainer

# Parse all OCMF entries from XML file
container = OcmfContainer.from_xml("charging_session.xml")

# Iterate over entries and verify signatures
for entry in container:
    print(f"Gateway: {entry.ocmf.payload.GI}")
    
    # Public key is automatically extracted from XML if present
    if entry.public_key:
        is_valid = entry.verify_signature()
        print(f"Signature: {'Valid' if is_valid else 'Invalid'}")

Supported Signature Algorithms

PyOCMF supports all ECDSA signature algorithms defined in the OCMF specification:

  • secp192k1, secp256k1 - Koblitz curves
  • secp192r1, secp256r1, secp384r1, secp521r1 - NIST curves
  • brainpool256r1, brainpoolP256r1, brainpool384r1 - Brainpool curves
  • SHA256 and SHA512 hash functions

Error Handling

from pyocmf import OCMF, SignatureVerificationError, OcmfFormatError

try:
    ocmf = OCMF.from_string(ocmf_string)
    is_valid = ocmf.verify_signature(public_key)
except OcmfFormatError as e:
    print(f"Invalid OCMF format: {e}")
except SignatureVerificationError as e:
    print(f"Signature verification error: {e}")

Development

# Clone the repository
git clone https://github.com/paul-ww/pyocmf.git
cd pyocmf

# Install dependencies with uv
uv sync

# Run tests
uv run pytest

# Run type checking
uv run ty check src test

# Run linting
uv run ruff check .

Documentation

License

See LICENSE file for details.

About OCMF

OCMF (Open Charge Metering Format) is a standardized format for metering data from electric vehicle charging stations. It ensures transparency and tamper-proof documentation of charging sessions, complying with legal requirements such as the EU Measuring Instruments Directive (MID) and German Eichrecht.

For more information about OCMF, visit safe-ev.de.


Vibe-engineered with Claude Code 🤖

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyocmf-0.2.2.tar.gz (24.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyocmf-0.2.2-py3-none-any.whl (37.3 kB view details)

Uploaded Python 3

File details

Details for the file pyocmf-0.2.2.tar.gz.

File metadata

  • Download URL: pyocmf-0.2.2.tar.gz
  • Upload date:
  • Size: 24.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pyocmf-0.2.2.tar.gz
Algorithm Hash digest
SHA256 b9fc9f3b3d5378b14133677cc4aefb84bd6ca41dfca364cf621600cc47c5f9f0
MD5 50f75354b35c14f4cc49808d1c3db72f
BLAKE2b-256 81518448267f4f8d02bc8429d081ef3b19c7cb73e3205b28a7c4ff6ccf0ad321

See more details on using hashes here.

File details

Details for the file pyocmf-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: pyocmf-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 37.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pyocmf-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 8a52fd5175cb909125f4512a7afab82bd44ce549ed1e572c64e8bd35c426be2b
MD5 2da2e610bd27af67befeacdec8569452
BLAKE2b-256 3bdf059d385faf3b53683fe7a9977b99ca910ea2d222749d10693de0e1e5fc15

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page