py20305
The IEEE 2030.5 / CSIP client of Project Satori — an LF Energy open-source project led by the SunSpec Alliance, DER Security, and industry consortium members.
An open IEEE 2030.5 client for distributed energy resources, with CSIP-AUS support. It speaks the utility's protocol so your device doesn't have to.
Point it at an IEEE 2030.5 server and it registers, discovers what the server exposes, runs the DERControl schedule it is given, applies the resulting setpoints to a device, and posts telemetry back.
Install
pip install py20305
The base install is the protocol client. Extras add what you may not need:
sunspec for Modbus devices, api for the HTTP management API, mqtt for
traffic forwarding, or all.
Running it as a service
pip install "py20305[cli,sunspec]"
py20305 --config client.yaml --check # validate, print your LFDI
py20305 --config client.yaml # run
One YAML or JSON file describes the server, the certificate and the devices. It
retries the connection while the server is down, registers itself only if the
server does not already know it, and stops cleanly on SIGTERM. See
Running a client
and examples/client.example.yaml.
Running it in a container
docker build -t py20305 .
docker run -d -v "$PWD/config:/etc/py20305:ro" py20305
The image carries the client and nothing else -- configuration and certificates
are mounted, never baked in. It runs unprivileged and stops in order on
SIGTERM. See Running in a container
and examples/docker-compose.yml.
Embedding it: talking to a server in five minutes
IEEE 2030.5 is mutual TLS throughout, and the server identifies your client by its certificate. Your LFDI — the identifier the utility registers — is derived from it:
from pathlib import Path
from py20305.security import compute_lfdi
print(compute_lfdi(Path("certs/client.pem").read_text()))
Give that to whoever runs the server, then:
python examples/quickstart.py \
--url https://server.example.com:8443 \
--cert certs/client.pem --key certs/client.key --ca certs/ca.pem
That drives the print connector, which needs no hardware — it logs the controls it would have applied. So you can exercise the whole discovery, event and telemetry path against a real server before an inverter is wired up.
Swap in SunSpecDeviceConfig when you have one. Full walkthrough in the
quickstart.
What's in it
| Protocol client | Resource discovery, registration, mTLS transport, retry with backoff, redirect probing, server timebase |
| Finding a server | DNS-SD query over mDNS or xmDNS when no server URL is configured, as IEEE 2030.5 §6.9.2 asks of a client; optional announcement of this client so an operator can find it on their own network |
| Event engine | DERControl five-state machine, supersession across programs, randomized start and duration, Response acknowledgments |
| Telemetry | DERStatus, DERCapability, DERSettings, DERAvailability, metered readings as MirrorUsagePoints, started and rediscovered for you by the runner |
| Connectors | SunSpec Modbus over TCP, RTU and TLS; a no-hardware print connector; your own by subclass or factory |
| Subscriptions | Subscribe/notify as an alternative to polling, with a notification listener |
| Runner | A CLI, config file, connection retry and signal-handled shutdown |
| Management API | Optional HTTP API for observing and nudging a running client |
| Forwarding | Optional MQTT publication of every captured exchange |
Standards
IEEE 2030.5-2018 and 2030.5-2023. Both XSDs ship with the package and
validation runs against them. The generated bindings track 2023; a
server_2018_compat flag adjusts behavior for servers still on 2018.
CSIP-AUS, including DOE (dynamic operating envelope) limits.
The client maps one certificate identity to one end device. It registers and drives that device, and does not fan a server-side EndDevice out across several local ones.
Certification
py20305 is not SunSpec CSIP certified, and using it does not make a product certified. Certification is a property of the product -- the assembled client device or system, tested as a whole -- not of a library inside it.
If you are building a client product that needs SunSpec CSIP certification, follow the SunSpec Alliance's certification process: IEEE 2030.5 / CSIP certification.
Project Satori
Any certified DER. Any utility program. Satori — “awakening” — is an open-source initiative to make any certified DER a compliant participant in utility DER programs: point it at the Modbus port of a UL 1741 SB device — inverter, battery, or EV — and it joins a program without a firmware rewrite. The bundle builds on SunSpec-certified implementations contributed by DER Security, and this repository is its IEEE 2030.5 half:
| Project | Role |
|---|---|
| PySunSpec2 | SunSpec Modbus reference library, used in more than 80% of inverter-based products shipped globally |
| py20305 (this repository) | IEEE 2030.5 client stack with CSIP and CSIP-AUS support, and a SunSpec Modbus bridge |
| SunSpec DevKit CE | Discover, read and identify SunSpec devices on the wire |
Documentation
https://dersecurity.github.io/py20305/
Development
pip install -e ".[dev]"
pytest tests -q # unit tests, no network
ruff check src tests examples scripts
mypy
mkdocs serve # docs at http://127.0.0.1:8000
There is also an end-to-end suite that runs this client against envoy, the open-source CSIP-AUS utility server from the Australian National University — the implementation ANU's certification program runs on. It needs Docker:
python scripts/e2e_server.py up
pytest tests/e2e -v
python scripts/e2e_server.py down
The unit suite proves this client does what we believe the standard requires. That one proves the belief survives contact with an implementation nobody here wrote. See Testing.
See CONTRIBUTING.md.
License
Metadata
Release files for py20305 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| py20305-0.6.0.tar.gz | 821.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| py20305-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.4 MB
Release files / py20305-0.6.0.tar.gz
| Download URL | py20305-0.6.0.tar.gz |
|---|---|
| Size | 821.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
72a516f7f3d532318d2899e9baa9d6bcb8f4966d83fad8655e39d286492ca5e1
|
|
BLAKE2b-256 checksum How to use checksums |
7a9eaef2feb4071d4d1ab224b0928ee7dcb1b382a9a2879e5b695af961ac9e94
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 8, 2026.
Transparency logRelease files / py20305-0.6.0-py3-none-any.whl
| Download URL | py20305-0.6.0-py3-none-any.whl |
|---|---|
| Size | 592.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
659cba78c0cb3bbe1818e3fd0c7f3947ecbb578f74638039d1e44ee71680b627
|
|
BLAKE2b-256 checksum How to use checksums |
a66bc0fd081557279ee66c04898db32d3b07eee8407c96156b22df6c166d62cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 8, 2026.
Transparency log